Aggiornamento di Discourse a Rails 6

Ciao Team,

Rails 6.0.0 è stato rilasciato 25 giorni fa, quindi penso sia il momento di aggiornare Discourse :slight_smile: Ci sono stati alcuni passaggi che ho dovuto eseguire per far funzionare tutto.

  1. Correggere gli spec interrotti
  • Aggiungere il metodo vuoto trigger_transactional_callbacks? a lib/mini_sql_multisite_connection.rb
  • UrlHelper sta caricando di default ActionView::Helpers::UrlHelper invece di lib/UrlHelper. L’ho risolto aggiungendo :: davanti, ma cosa ne pensate di cambiare il nome di quella classe?
  • In Rails 5.2.3 MigrationContext accettava un argomento, in 6.0.0 è richiesto uno schema aggiuntivo
  1. Correggere i metodi deprecati
  1. Utilizzare il caricatore classico come primo passo prima di Zeitwerk
  2. Corretto le migrazioni su Rails 6.0.0 - la versione più recente di Rails non permette errori nelle vecchie migrazioni (non è possibile definire una colonna già definita ‘integer’)

Ho eseguito test di fumo per verificare che Discourse funzioni come previsto. Inoltre, ho eseguito test di prestazioni per assicurarmi che non ci siano regressioni (ho utilizzato 500 iterazioni di default).

Test Rails 5.2.3 Rails 6.0.0 Percentuale
categories-50 27 24 88,89%
categories-75 31 26 83,87%
categories-90 36 37 102,78%
categories-99 52 50 96,15%
home-50 27 26 96,30%
home-75 30 28 93,33%
home-90 39 38 97,44%
home-99 53 55 103,77%
topic-50 35 27 77,14%
topic-75 36 29 80,56%
topic-90 37 39 105,41%
topic-99 56 50 89,29%
categories_admin-50 47 47 100,00%
categories_admin-75 54 59 109,26%
categories_admin-90 64 66 103,13%
categories_admin-99 132 116 87,88%
home_admin-50 47 46 97,87%
home_admin-75 51 56 109,80%
home_admin-90 63 64 101,59%
home_admin-99 110 97 88,18%
topic_admin-50 50 49 98,00%
topic_admin-75 58 59 101,72%
topic_admin-90 65 67 103,08%
topic_admin-99 113 86 76,11%
load_rails 2593 2618 100,96%
rss_kb 318800 287332 90,13%
pss_kb 306913 275378 89,73%
Media 89,31%

Creerò una pull request con tutte le modifiche menzionate sopra. Fate sapere se desiderate che aggiusti qualcosa o che esegua ulteriori test per garantire che tutto funzioni come previsto.

PR - DEV: Upgrading Discourse to Rails 6 by KrisKotlarek · Pull Request #8083 · discourse/discourse · GitHub

Saluti,
Kris

Questo è fantastico :confetti_ball:

Puoi metterlo in una tabella markdown con la variazione percentuale? Una rapida occhiata mostra che non è cambiato molto, il che è fantastico.

Per quanto riguarda i plugin, abbiamo un rake task che installa tutti i plugin ufficiali: puoi eseguirlo e verificare che le specifiche dei plugin siano soddisfatte su Rails 6? (rake plugin:spec dovrebbe fare al caso nostro)

Ho aggiornato il post originale per mostrare la tabella. Grazie per avermi indicato le specifiche dei plugin. Vedo che 2 specifiche sono fallite su Travis; le esaminerò e le correggerò.

Ci sono 2 numeri qui che trovo molto interessanti:

L’RSS su 6.0 è quasi 10% migliore.

Topic (tempo mediano) - che è il nostro percorso più comune - è 22% più veloce.

Si tratta di prestazioni seriamente migliorate. Riesci a misurare in modo coerente un miglioramento del 22% su topic-50? Puoi confermare che la pagina effettiva si sta rendendo correttamente?

Ho eseguito il benchmark 3 volte e questa volta i risultati sono meno spettacolari. Il mio flusso consiste nel digitare ruby script/bench.rb nel branch corretto (master o rails6), premere Invio e non toccare la tastiera per non influenzare i risultati.

topic-50 RSS
5.2.3 50 322852
5.2.3 50 309684
5.2.3 50 346376
Media 50 326304
6.0.0 49 328844
6.0.0 49 321824
6.0.0 49 283584
Media 49 311417

Ho anche collegato il mio server di sviluppo al database delle prestazioni per assicurarmi che la pagina dell’argomento appaia corretta. Lo screenshot qui sotto mi sembra a posto.

Vorrei avere il tuo parere su una correzione.
Ho scaricato tutti i plugin, ma una nuova specifica fallisce rispetto a master (./plugins/discourse-data-explorer/spec/controllers/queries_controller_spec.rb:32)

  1) DataExplorer::QueryController when disabled denies every request
     Failure/Error: render 'default/empty'

     ActionView::Template::Error:
       wrong number of arguments (given 2, expected 1)

Questo è stato corretto in master rspec-rails https://github.com/rspec/rspec-rails/blob/4-0-dev/lib/rspec/rails/view_rendering.rb
modificando
def self.call(_template) in def self.call(_template, _source = nil)

Potrei applicare una patch monkey a rspec-rails creando un nuovo file in lib/freedom_patched/rspec-rails.rb, ma volevo assicurarmi che questo sia l’approccio migliore.

Penso che questo sia l’ultimo cambiamento che impedisce l’unione di Rails 6.

Inoltre, ho notato che questa specifica è rotta, ma lo è anche in master; posso provare a correggerla (./plugins/discourse-calendar/spec/jobs/update_holiday_usernames_spec.rb:14)

 Failure/Error: expect(DiscourseCalendar.users_on_holiday).to eq([post.user.username])
       expected: ["bruce1"]
            got: []

Infine, ci sono metodi deprecati nei plugin che posso facilmente correggere domani.

Qual è il tuo parere su rspec-rails?

Oh mio Dio, immagino che dovremo fare monkey patch fino al rilascio di rspec-rails 4; non riesco a pensare a una soluzione più pulita qui.

O forse… potremmo… usare il gem beta per ora, se tutto funziona?

Capito, provo a installare la versione beta stasera e vediamo come va. Potrebbe essere un aggiornamento facile e senza intoppi.

Ho apportato alcune correzioni aggiuntive.

Prima di tutto, ho scoperto perché un test falliva per me sia nel ramo master che in quello rails6 - FIX: Freezed time used in update_holiday_usernames_spec.rb should be UTC by KrisKotlarek · Pull Request #3 · discourse/discourse-calendar · GitHub

Ho inoltre creato delle pull request per i metodi deprecati in vari plugin:

Ho fatto il rebase dell’ultimo master nel ramo rails6

Infine, ho aggiornato rspec-rails alla versione 4.0.0.beta2 e funziona correttamente sulla mia macchina locale. Travis ha riscontrato alcuni problemi, tuttavia vedo gli stessi problemi anche in altre pull request, quindi non credo che siano correlati all’aggiornamento di rspec-rails.

Questo è stato unito :confetti_ball: :confetti_ball: :confetti_ball:

Oggi terrò un occhio attento su di esso, grazie mille per questo lavoro.

E un grande grazie al team di Rails per aver reso questo aggiornamento così piacevole!!

Tornerò su questo argomento con alcuni bei grafici.

L’aggiornamento sembra piuttosto tranquillo, il che è ottimo. Le prestazioni sono costanti e rimangono incredibilmente simili.

Memoria e CPU appaiono notevolmente simili.

La mia unica preoccupazione (e qualcosa che vorrei chiarire) è che sembrano esserci thread “impazziti” per alcuni secondi regolarmente sui web worker.

In qualche modo, alcune richieste causano la creazione di un numero enorme di thread che poi scompaiono.

Continuerò a indagare su questo: dobbiamo ottenere gli stack trace quando il numero è alto, così da poter individuare il colpevole.

Visto che tutto il resto sembra andare davvero bene, non procederò al rollback dell’aggiornamento.

Questo dovrebbe essere corretto come da:

Questo è il risultato di un nuovo codice in Rails 6 che protegge l’accesso alla variabile legata al thread che determina se è possibile utilizzare le prepared statement o meno.

In Discourse non utilizziamo affatto le prepared statement, quindi questa patch non è qualcosa di cui abbiamo bisogno.

Per maggiori informazioni, vedi:

E … confermato … la mia correzione elimina l’ampia quantità di picchi di thread

Da notare anche … ecco come ho fatto il debug:

  1. Ho scritto questa piccola classe
# frozen_string_literal: true

class Thread
  attr_accessor :origin
end

class ThreadDetective
  def self.test_thread
    Thread.new { sleep 1 }
  end
  def self.start(max_threads)
    @thread ||= Thread.new do
      self.new.monitor(max_threads)
    end

    @trace = TracePoint.new(:thread_begin) do |tp|
      Thread.current.origin = Thread.current.inspect
    end
    @trace.enable
  end

  def self.stop
    @thread&.kill
    @thread = nil
    @trace&.disable
    @trace.stop
  end

  def monitor(max_threads)
    STDERR.puts "Monitoring threads in #{Process.pid}"

    while true
      threads = Thread.list

      if threads.length > max_threads
        str = +("-" * 60)
        str << "#{threads.length} found in Process #{Process.pid}!\n"

        threads.each do |thread|
          str << "\n"
          if thread.origin
            str << thread.origin
          else
            str << thread.inspect
          end
          str << "\n"
        end
        str << ("-" * 60)

        STDERR.puts str
      end
      sleep 1
    end
  end

end
  1. Ho quindi collegato in unicorn after_fork un require di questa classe ed eseguito ThreadDetective.start(14)

  2. La classe ha monitorato diligentemente ogni volta che veniva creato un thread utilizzando un TracePoint e ha inserito un piccolo frame sul thread chiamato origin per aiutarmi a tracciare da dove proveniva. Una volta osservato un gran numero di thread, ha scaricato i dati su STDERR. Questo può essere tracciato in /var/www/discourse/logs/unicorn.stderr.log

Una volta saputo che 100 thread provenivano tutti da un singolo punto, è stato molto facile isolare la causa principale.

Ho notato che non posso più usare dev.local come hostname in modalità di sviluppo in Rails 6, quindi ho aggiunto una variabile ENV per configurare quella whitelist:

Non dovremmo dover mantenere questo monkey patch a lungo termine, dato che abbiamo appena introdotto una correzione in Rails.

Ciao,

grazie per il tuo impegno nel portare Rails 6 su Discourse! Posso chiederti gentilmente quando ci si aspetta che questo venga integrato in Discourse? O è già presente nella versione 2.4.0.beta? Chiedo solo per sapere se potrebbe rompere eventuali plugin installati dagli utenti sulle loro istanze.

Cordiali saluti,
Andreas.

È attivo da settembre per tutti gli utenti che utilizzano il canale di rilascio predefinito. È stato introdotto per la prima volta nella versione 2.4.0.beta5.

Va bene, grazie mille. I migliori auguri per il 2020 e grazie per tutto ciò che state facendo qui.