Mise à niveau de Discourse vers Rails 6

Bonjour l’équipe,

Rails 6.0.0 a été publié il y a 25 jours, je pense donc qu’il est temps de mettre à jour Discourse :slight_smile: J’ai dû effectuer quelques étapes pour que cela fonctionne.

  1. Corriger les spécifications cassées
  • Ajouter une méthode vide trigger_transactional_callbacks? dans lib/mini_sql_multisite_connection.rb
  • UrlHelper charge par défaut ActionView::Helpers::UrlHelper au lieu de lib/UrlHelper. Je l’ai résolu en ajoutant :: devant, mais que pensez-vous de changer le nom de cette classe ?
  • Dans Rails 5.2.3, MigrationContext acceptait un argument, tandis que dans 6.0.0, un schéma supplémentaire est requis.
  1. Corriger les méthodes obsolètes
  • update_attributes! a été remplacé par update!
  • Content_type contiendra désormais le jeu de caractères ; il faut utiliser le type de média à la place - rails/guides/source/upgrading_ruby_on_rails.md at main · rails/rails · GitHub
  • Corriger l’avertissement concernant la constante déjà initialisée (TRADITIONAL_ESCAPED_CHAR, RFC_5987_ESCAPED_CHAR). Avant de les supprimer, j’ai confirmé que les valeurs dans ActionPack étaient identiques.
  1. Utiliser le chargeur automatique classique comme première étape avant Zeitwerk.
  2. Corriger les migrations sur Rails 6.0.0 - la version la plus récente de Rails ne permet plus l’erreur présente dans les anciennes migrations (vous ne pouvez pas définir une colonne déjà définie ‘integer’).

J’ai effectué des tests de fumée pour vérifier que Discourse fonctionne comme prévu. De plus, j’ai exécuté des tests de performance pour m’assurer qu’il n’y a pas de régression (j’ai utilisé 500 itérations par défaut).

Test Rails 5.2.3 Rails 6.0.0 Pourcentage
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%
Moyenne 89,31%

Je vais créer une pull request avec tous les changements mentionnés ci-dessus. Veuillez me faire savoir si vous souhaitez que j’ajuste quelque chose ou que j’effectue des tests supplémentaires pour garantir que tout fonctionne comme prévu.

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

Cordialement,
Kris

C’est génial :confetti_ball:

Peux-tu mettre cela dans un tableau Markdown avec le pourcentage de changement ? Un coup d’œil rapide montre que peu de choses ont changé, ce qui est formidable.

Côté plugins, nous avons une tâche rake qui installe tous les plugins officiels. Peux-tu l’exécuter et t’assurer que les spécifications des plugins passent sur Rails 6 ? (La commande rake plugin:spec devrait suffire)

J’ai mis à jour le message d’origine pour afficher le tableau. Merci de m’avoir indiqué les spécifications des plugins. Je vois que deux spécifications ont échoué sur Travis ; je vais les examiner et les corriger.

Il y a deux chiffres ici que je trouve très intéressants :

Le RSS sur la version 6.0 est presque 10 % meilleur.

Le sujet (temps médian) – qui est notre itinéraire le plus courant – est 22 % plus rapide.

C’est une amélioration de performance vraiment sérieuse. Pouvez-vous mesurer de manière constante une vitesse de 22 % supérieure sur topic-50 ? Pouvez-vous confirmer que la page elle-même se rend correctement ?

J’ai exécuté le benchmark 3 fois et cette fois, les résultats sont moins spectaculaires. Mon processus consiste à taper ruby script/bench.rb dans la bonne branche master ou rails6, appuyer sur Entrée et ne pas toucher au clavier pour ne pas fausser les résultats.
| | topic-50 | RSS |
| — | — | — | — |
| 5.2.3 | 50 | 322852 |
| 5.2.3 | 50 | 309684 |
| 5.2.3 | 50 | 346376 |
| Moyenne | 50 | 326304 |
| 6.0.0 | 49 | 328844 |
| 6.0.0 | 49 | 321824 |
| 6.0.0 | 49 | 283584 |
| Moyenne | 49 | 311417 |

J’ai également connecté mon serveur de développement à la base de données de performance pour m’assurer que la page du sujet s’affiche correctement. La capture d’écran ci-dessous me semble correcte.

J’aimerais avoir votre avis sur une correction.
J’ai téléchargé tous les plugins, mais une nouvelle spécification échoue par rapport à la branche 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)

Cela est corrigé dans la branche master rspec-rails https://github.com/rspec/rspec-rails/blob/4-0-dev/lib/rspec/rails/view_rendering.rb
en modifiant
def self.call(_template) en def self.call(_template, _source = nil)

Je pourrais appliquer un monkey patch sur rspec-rails avec un nouveau fichier dans lib/freedom_patched/rspec-rails.rb, mais je voulais m’assurer que c’est la meilleure approche.

Je pense que c’est le dernier changement qui empêche la fusion de Rails 6.

De plus, j’ai remarqué que cette spécification est cassée, mais elle l’est aussi sur la branche master. Je peux essayer de la corriger (./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: []

Enfin, il y a des méthodes obsolètes dans les plugins que je peux facilement corriger demain.

Quel est votre avis sur rspec-rails ?

Oh là là, je suppose qu’on va devoir faire du monkey patch jusqu’à la sortie de rspec-rails 4, je ne vois pas de solution plus propre pour l’instant.

Ou alors… peut-être… utiliser le gem bêta pour l’instant si tout fonctionne ?

C’est noté, je vais essayer d’installer la version bêta ce soir et voir comment ça se passe. Cela pourrait être une mise à jour facile et fluide.

J’ai apporté quelques corrections supplémentaires.

Tout d’abord, j’ai identifié pourquoi un test échouait pour moi à la fois sur la branche master et sur la branche rails6 - FIX: Freezed time used in update_holiday_usernames_spec.rb should be UTC by KrisKotlarek · Pull Request #3 · discourse/discourse-calendar · GitHub

J’ai également créé des demandes de tirage (pull requests) pour des méthodes obsolètes dans divers plugins :

J’ai réintégré la dernière version de master dans la branche rails6.

Enfin, j’ai mis à jour rspec-rails vers la version 4.0.0.beta2 et cela fonctionne bien sur ma machine locale. Travis rencontre toutefois certains problèmes ; cependant, je constate les mêmes problèmes dans d’autres demandes de tirage, donc je ne pense pas qu’ils soient liés à la mise à niveau de rspec-rails.

C’est maintenant fusionné :confetti_ball: :confetti_ball: :confetti_ball:

Je vais surveiller cela de près aujourd’hui, merci beaucoup pour ce travail.

Et un grand merci à l’équipe Rails pour avoir rendu cette mise à jour si agréable !!

Je reviendrai sur ce sujet avec quelques beaux graphiques.

La mise à jour se déroule de manière plutôt calme, ce qui est excellent. Les performances sont stables et restent incroyablement similaires.

La mémoire et le processeur présentent des profils remarquablement similaires.

Ma seule inquiétude (et un point que je souhaite élucider) est l’apparition régulière, pendant quelques secondes, de threads « incontrôlés » sur les web workers.

Donc, d’une manière ou d’une autre, certaines requêtes provoquent le lancement d’un grand nombre de threads qui disparaissent ensuite.

Je continuerai d’enquêter sur ce point ; nous devons obtenir des traces d’exécution (backtraces) lorsque le nombre est élevé, afin de pouvoir identifier le coupable.

Compte tenu du fait que tout le reste semble très bon, je ne procéderai pas à un retour en arrière sur la mise à jour.

Cela devrait être corrigé selon :

Ceci est le résultat d’un nouveau code dans Rails 6 qui protège l’accès à la variable liée au thread déterminant si vous pouvez utiliser des instructions préparées ou non.

Chez Discourse, nous n’utilisons pas du tout d’instructions préparées, donc ce correctif n’est pas quelque chose dont nous avons besoin.

Pour en savoir plus, consultez :

Et … confirmé … ma correction élimine le grand nombre de pics de threads

Il est également utile de noter … voici comment je l’ai débogué :

  1. J’ai écrit cette petite 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 "Surveillance des threads dans #{Process.pid}"

    while true
      threads = Thread.list

      if threads.length > max_threads
        str = +("-" * 60)
        str << "#{threads.length} trouvés dans le processus #{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. J’ai ensuite intégré dans unicorn after_fork un require de cette classe et exécuté ThreadDetective.start(14)

  2. La classe a surveillé attentivement à chaque fois qu’un thread était créé en utilisant un TracePoint et a ajouté un petit cadre au thread appelé origin pour m’aider à suivre son origine. Une fois qu’un grand nombre de threads a été observé, elle a vidé les informations sur STDERR. Cela peut être suivi dans /var/www/discourse/logs/unicorn.stderr.log

Une fois que j’ai su que les 100 threads provenaient tous d’un seul endroit, il a été très facile d’isoler la cause racine.

J’ai remarqué que je ne pouvais plus utiliser dev.local comme nom d’hôte en mode développement dans Rails 6. J’ai donc ajouté une variable d’environnement pour configurer cette liste blanche :

Nous ne devrions pas avoir besoin de maintenir ce correctif de contournement à long terme, car nous avons tout juste intégré une correction dans Rails.

Bonjour,

merci pour vos efforts visant à intégrer Rails 6 dans Discourse ! Puis-je humblement demander quand cela devrait être intégré dans Discourse ? Ou est-ce déjà présent dans la version 2.4.0.beta ? Je me demande simplement si cela pourrait casser des plugins installés sur les instances des utilisateurs.

Cordialement,
Andreas.

Cela est en production depuis septembre pour tous ceux qui utilisent le canal de publication par défaut. Cela a été présenté pour la première fois dans la version 2.4.0.beta5.

Très bien, merci beaucoup. Meilleurs vœux pour 2020 et merci pour tout ce que vous faites ici.