Actualización de Discourse a Rails 6

Hola Equipo,

Rails 6.0.0 se lanzó hace 25 días, así que creo que es hora de actualizar Discourse :slight_smile: Hubo algunos pasos que necesité realizar para que funcionara.

  1. Corregir pruebas (specs) rotas
  • Agregar el método vacío trigger_transactional_callbacks? a lib/mini_sql_multisite_connection.rb
  • UrlHelper está cargando por defecto ActionView::Helpers::UrlHelper en lugar de lib/UrlHelper. Lo solucioné agregando :: al principio, sin embargo, ¿qué opinan sobre cambiar el nombre de esa clase?
  • En Rails 5.2.3, MigrationContext aceptaba un argumento; en 6.0.0 se requiere un esquema adicional.
  1. Corregir métodos obsoletos
  1. Usar el autoloader clásico como primer paso antes de Zeitwerk.
  2. Corregir migraciones en Rails 6.0.0: la versión más reciente de Rails no permite errores de migraciones antiguas (no puedes definir una columna ya definida como ‘integer’).

Realicé pruebas de humo para verificar que Discourse funcione como se espera. Además, ejecuté pruebas de rendimiento para asegurar que no haya regresiones (utilicé las 500 iteraciones predeterminadas).

Prueba Rails 5.2.3 Rails 6.0.0 Porcentaje
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%
Promedio 89.31%

Crearé una solicitud de extracción (pull request) con todos los cambios mencionados anteriormente. Por favor, háganme saber si desean que ajuste algo o que realice pruebas adicionales para asegurar que todo funcione como se espera.

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

Saludos,
Kris

¡Esto es increíble :confetti_ball:!

¿Podrías poner esto en una tabla de Markdown con el cambio porcentual? Una mirada rápida indica que no ha cambiado mucho, lo cual es genial.

En cuanto a los complementos, tenemos una tarea rake que instala todos los complementos oficiales; ¿podrías ejecutarla y asegurarte de que las especificaciones de los complementos pasen en Rails 6? (rake plugin:spec debería funcionar).

He actualizado la publicación original para mostrar la tabla. Gracias por indicarme las especificaciones de los plugins. Veo que dos especificaciones fallaron en Travis; las revisaré y las corregiré.

Hay dos números aquí que me resultan muy interesantes:

El RSS en la versión 6.0 es casi un 10% mejor.

El tema (tiempo mediano), que es nuestra ruta más común, es un 22% más rápido.

Esto es un rendimiento realmente mejorado. ¿Puedes medir consistentemente un 22% más rápido en topic-50? ¿Puedes confirmar que la página real se está renderizando correctamente?

Ejecuté el benchmark 3 veces y esta vez, los resultados son menos espectaculares. Mi flujo consiste en escribir ruby script/bench.rb en la rama correcta master o rails6, presionar Enter y no tocar el teclado para no afectar los resultados.

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

También conecté mi servidor de desarrollo a la base de datos de rendimiento para asegurarme de que la página de tema se vea correctamente. La captura de pantalla de abajo me parece bien.

Me gustaría conocer tu opinión sobre una corrección.

He descargado todos los plugins, pero una nueva especificación está fallando en comparación con master (./plugins/discourse-data-explorer/spec/controllers/queries_controller_spec.rb:32):

  1) DataExplorer::QueryController cuando está deshabilitado niega todas las solicitudes
     Failure/Error: render 'default/empty'

     ActionView::Template::Error:
       número incorrecto de argumentos (se proporcionaron 2, se esperaba 1)

Eso está corregido en master rspec-rails https://github.com/rspec/rspec-rails/blob/4-0-dev/lib/rspec/rails/view_rendering.rb
cambiando
def self.call(_template) por def self.call(_template, _source = nil)

Podría aplicar un parche de mono (monkey patch) a rspec-rails con un nuevo archivo en lib/freedom_patched/rspec-rails.rb, pero quería asegurarme de que este sea el mejor enfoque.

Creo que este es el último cambio que está bloqueando la integración de Rails 6.

Además, noté que esta especificación está rota, aunque también lo está en master. Puedo intentar corregirla (./plugins/discourse-calendar/spec/jobs/update_holiday_usernames_spec.rb:14):

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

Finalmente, hay métodos obsoletos en los plugins que puedo corregir fácilmente mañana.

¿Cuál es tu opinión sobre rspec-rails?

¡Vaya! Supongo que aplicaremos parches en el código (monkey patch) hasta que se lance rspec-rails 4; no se me ocurre ninguna solución más limpia aquí.

O… tal vez… ¿usar la versión beta del gem por ahora si todo funciona?

Entendido, dejaré que intente instalar la versión beta esta noche y veré cómo va. Podría ser una actualización fácil y sin problemas.

He realizado algunas correcciones adicionales.

En primer lugar, descubrí por qué una prueba fallaba en mi entorno tanto en la rama master como en la rama rails6 - FIX: Freezed time used in update_holiday_usernames_spec.rb should be UTC by KrisKotlarek · Pull Request #3 · discourse/discourse-calendar · GitHub

También he creado solicitudes de extracción (pull requests) para métodos obsoletos en varios plugins:

He rebasado la última versión de master en la rama rails6.

Por último, he actualizado rspec-rails a la versión 4.0.0.beta2 y funciona correctamente en mi máquina local. Sin embargo, Travis ha tenido algunos problemas; aunque veo los mismos problemas en otras solicitudes de extracción, así que no creo que estén relacionados con la actualización de rspec-rails.

¡Esto ya está fusionado! :confetti_ball: :confetti_ball: :confetti_ball:

Voy a estar muy atento a ello hoy. Muchas gracias por este trabajo.

Y un gran agradecimiento al equipo de Rails por hacer de esta actualización algo tan agradable!!

Volveré a informar sobre este tema con algunas gráficas bastante bonitas.

La actualización parece bastante tranquila, lo cual es genial. El rendimiento es uniforme y se mantiene increíblemente similar.

La memoria y la CPU muestran un comportamiento notablemente similar.

Mi única preocupación (y algo que me gustaría resolver) es que parece que tenemos hilos “desbocados” durante unos segundos de forma regular en los web workers.

De alguna manera, algunas solicitudes están causando que se generen y luego desaparezcan una gran cantidad de hilos.

Continuaré investigando esto; necesitamos obtener los backtraces cuando el número sea alto para poder identificar al culpable.

Dado que todo lo demás se ve realmente bien, no revertiré la actualización.

Esto debería corregirse según:

Esto es resultado de un nuevo código en Rails 6 que protege el acceso a la variable ligada al hilo que determina si se pueden usar sentencias preparadas o no.

En Discourse no utilizamos sentencias preparadas en absoluto, por lo que este parche no es algo que necesitemos.

Ver más en:

Y … confirmado … mi corrección elimina la gran cantidad de picos de hilos

También vale la pena mencionar … así es como lo depuré:

  1. Escribí esta pequeña clase
# 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 "Monitoreando hilos en #{Process.pid}"

    while true
      threads = Thread.list

      if threads.length > max_threads
        str = +("-" * 60)
        str << "#{threads.length} encontrados en el proceso #{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. Luego conecté en unicorn after_fork un require de esta clase y ejecuté ThreadDetective.start(14)

  2. La clase vigiló diligentemente cada vez que se creaba un hilo usando un TracePoint y colocó un pequeño marco en el hilo llamado origin para ayudarme a rastrear su origen. Una vez que se observó un gran número de hilos, volcó la información a STDERR. Esto se puede rastrear en /var/www/discourse/logs/unicorn.stderr.log

Una vez que supe que los 100 hilos provenían de un solo lugar, fue muy fácil aislar la causa raíz.

Noté que ya no puedo usar dev.local como nombre de host en modo de desarrollo en Rails 6, así que he añadido una variable de entorno para configurar esa lista blanca:

No deberíamos mantener este parche temporal a largo plazo, ya que acabamos de implementar una solución en Rails.

Hola,

gracias por tus esfuerzos en traer Rails 6 a Discourse. ¿Podría preguntarte humildemente cuándo se espera que esto llegue a Discourse? ¿O ya está en la versión 2.4.0.beta? Solo me interesa saber si esto podría romper algún plugin que las personas tengan instalado en sus instancias.

Saludos cordiales,
Andreas.

Esto está en vivo desde septiembre para todos los usuarios del canal de lanzamiento predeterminado. Fue presentado por primera vez en la versión 2.4.0.beta5.

Muy bien, muchas gracias. Mis mejores deseos para 2020 y gracias por todo lo que están haciendo aquí.