チームの皆様、こんにちは
Rails 6.0.0 は 25 日前にリリースされましたので、Discourse のアップデートを行う時期だと思います 動作させるためにいくつかの手順が必要でした。
壊れた specs の修正
lib/mini_sql_multisite_connection.rb に空のメソッド trigger_transactional_callbacks? を追加
UrlHelper がデフォルトで lib/UrlHelper ではなく ActionView::Helpers::UrlHelper を読み込んでいました。これを解決するために先頭に :: を追加しましたが、そのクラス名を変更することについてどうお考えでしょうか?
Rails 5.2.3 の MigrationContext は 1 つの引数を受け入れていましたが、6.0.0 では追加の schema が必要になりました
非推奨メソッドの修正
Zeitwerk を導入する前に、まずクラシックな autoloader を使用する
Rails 6.0.0 でのマイグレーションを修正 - 最新の Rails は古いマイグレーションからの誤り(すでに定義済みのカラム ‘integer’ を定義すること)を許可しません
Discourse が期待通りに動作するようスモークテストを行いました。さらに、回帰がないことを確認するためにパフォーマンステストを実行しました(デフォルトの 500 反復を使用しました)。
テスト
Rails 5.2.3
Rails 6.0.0
パーセント
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%
平均
89.31%
上記のすべての変更を含むプルリクエストを作成します。何か調整が必要か、またはすべてが期待通りに動作することを確認するための追加テストが必要かどうか、お知らせください。
PR - DEV: Upgrading Discourse to Rails 6 by KrisKotlarek · Pull Request #8083 · discourse/discourse · GitHub
よろしくお願いいたします
Kris
sam
(Sam Saffron)
2019 年 9 月 9 日午前 7:56
2
これは素晴らしいです
これをパーセンテージ変化を含む Markdown の表にまとめていただけますか?ざっと見た限り、大きな変化はないようですが、それは素晴らしいことです。
プラグインに関しては、すべての公式プラグインをインストールする rake タスク があります。それを実行して、Rails 6 上でプラグインの仕様テストがパスすることを確認していただけますか?(rake plugin:spec でできるはずです)
元の投稿をテーブル表示に更新しました。プラグインの仕様を指摘していただきありがとうございます。Travis で 2 つの仕様が失敗しているのを見ましたので、確認して修正いたします。
sam
(Sam Saffron)
2019 年 9 月 9 日午前 9:38
4
ここに非常に興味深い 2 つの数値があります:
6.0 の RSS はほぼ 10% 向上しています。
トピック(中央値時間)— 私たちの最も一般的なルートですが、22% 高速化しています。
これは非常に顕著なパフォーマンス向上です。topic-50 で 22% の高速化を一貫して測定できますか?実際のページが正しくレンダリングされていることを確認できますか?
ベンチマークを3回実行しましたが、今回は結果がそれほど劇的ではありませんでした。私の手順は、正しいブランチ(master または rails6)で ruby script/bench.rb と入力し、Enter を押してキーボードに触れず、結果に影響を与えないようにすることです。
| | topic-50 | RSS |
| — | — | — | — |
| 5.2.3 | 50 | 322852 |
| 5.2.3 | 50 | 309684 |
| 5.2.3 | 50 | 346376 |
| 平均 | 50 | 326304 |
| 6.0.0 | 49 | 328844 |
| 6.0.0 | 49 | 321824 |
| 6.0.0 | 49 | 283584 |
| 平均 | 49 | 311417 |
また、トピックページが正しく表示されていることを確認するため、開発サーバーをパフォーマンスデータベースに接続しました。以下のスクリーンショットは問題ないと思います。
ある修正についてご意見を伺いたいです。
すべてのプラグインをダウンロードしましたが、1 つの新しい仕様(./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)
これはマスターで修正されています(rspec-rails https://github.com/rspec/rspec-rails/blob/4-0-dev/lib/rspec/rails/view_rendering.rb)。
def self.call(_template) を def self.call(_template, _source = nil) に変更することで対応しています。
lib/freedom_patched/rspec-rails.rb に新しいファイルを追加して rspec-rails をモンキーパッチすることもできますが、これが最善のアプローチか確認したかったです。
これが Rails 6 のマージを妨げている最後の修正だと思います。
さらに、この仕様は壊れていますが、マスターでも同様に壊れていることに気づきました(./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: []
これを修正することもできます。
最後に、プラグイン内で非推奨のメソッドがいくつかありますが、明日にでも簡単に修正できます。
rspec-rails についてのご意見をお聞かせください。
sam
(Sam Saffron)
2019 年 9 月 11 日午前 12:44
7
まあ、rspec-rails 4 がリリースされるまでモッキパッチを適用するしかなさそうですね。ここでよりクリーンな解決策は思いつきません。
あるいは……もしすべてが動作しているなら、とりあえずベータ版の gem を使うのはどうでしょうか?
了解しました。今夜ベータ版をインストールして様子を見てみます。スムーズに更新できるかもしれません。
いくつかの追加修正を行いました。
まず、master ブランチと rails6 ブランチの両方で1つの仕様テストが失敗していた原因を特定しました - FIX: Freezed time used in update_holiday_usernames_spec.rb should be UTC by KrisKotlarek · Pull Request #3 · discourse/discourse-calendar · GitHub
また、様々なプラグインで非推奨となったメソッドに対するプルリクエストを作成しました:
最新の master を rails6 ブランチにリベースしました。
最後に、rspec-rails をバージョン 4.0.0.beta2 に更新しましたが、ローカルマシンでは問題なく動作しています。Travis にはいくつかの問題が発生しましたが、他のプルリクエストでも同様の問題が見られるため、rspec-rails のアップグレードとは関連していないと考えています。
sam
(Sam Saffron)
2019 年 9 月 12 日午前 12:45
10
マージ完了しました
本日は引き続き注視していきます。この作業、本当にありがとうございます。
また、このような快適なアップグレードを実現してくださった Rails チームにも心から感謝します!!
このトピックについては、いくつかの見やすいグラフを交えて改めて報告します。
sam
(Sam Saffron)
2019 年 9 月 12 日午前 5:47
11
アップグレードは非常に平穏で、それは素晴らしいことです。パフォーマンスは均一で、以前と比べて驚くほど変わりません。
メモリとCPUの使用状況も非常に似ています。
唯一の懸念点(そして解明したい点)は、Webワーカーで定期的に数秒間「ランアウェイ」スレッドが発生しているように見えることです。
つまり、何らかのリクエストが大量のスレッドを生成し、すぐに消滅させているようです。
引き続き調査を進めます。スレッド数が多くなった際にバックトレースを取得し、原因を特定する必要があります。
他の点については非常に良好なため、アップグレードをロールバックすることはありません。
sam
(Sam Saffron)
2019 年 9 月 12 日午前 7:36
12
これは以下で修正されるべきです:
committed 07:34AM - 12 Sep 19 UTC
This is a temporary workaround for the issue in https://github.com/rails/rails/p… ull/36949
Discussing a proper fix in Rails with the Rails team.
Prior to this fix we were spinning up a thread every time we closed a connection
to the db.
これは、Rails 6 の新しいコードの結果であり、スレッドバインド変数へのアクセスを保護し、プリペアドステートメントを使用できるかどうかを判断するものです。
Discourse ではプリペアドステートメントを一切使用していないため、このパッチは必要ありません。
詳細は以下をご覧ください:
master ← 97jaz:thread-local-prepared-statements
@rafaelfranca / @matthewd
There is a slight unintended consequence to this … change I will monkey patch out of Discourse.
The implementation of RubyThreadLocalVar wacks a finalizer on the object, the finalizer spins a thread.
https://github.com//blob/bbeacbcebf72668ed04df0738df7e3a654f7c177/lib/concurrent/atomic/ruby_thread_local_var.rb#L101-L111
We use no prepared statements, but are now paying the penalty of spinning up a thread every time a connection is closed.
This has this impact on my graphs for the big multisites:
https://meta.discourse.org/t/upgrading-discourse-to-rails-6/128004/11?u=sam
Since once false this thing can never be turned true I will just implement an Immutable ThreadLocalVar class here for the cases where prepared statements are false. (bind anything but current value and it raises.
```diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 91d5d08121..970a1f9e8f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -114,6 +114,18 @@ def self.quoted_table_names # :nodoc:
@quoted_table_names ||= {}
end
+ class StaticThreadLocalVar
+ attr_reader :value
+
+ def initialize(value)
+ @value = value
+ end
+
+ def bind(value)
+ raise "attempting to change immutable local var" if value != @value
+ yield if block_given?
+ end
+ end
+
def initialize(connection, logger = nil, config = {}) # :nodoc:
super()
@@ -132,7 +144,7 @@ def initialize(connection, logger = nil, config = {}) # :nodoc:
@prepared_statement_status = Concurrent::ThreadLocalVar.new(true)
@visitor.extend(DetermineIfPreparableVisitor)
else
- @prepared_statement_status = Concurrent::ThreadLocalVar.new(false)
+ @prepared_statement_status = StaticThreadLocalVar.new(false)
end
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
```
Thoughts? Should we patch this in Rails?
sam
(Sam Saffron)
2019 年 9 月 12 日午前 10:21
13
そして……確認しました……私の修正で大量のスレッドスパイクが解消されました
また、参考までに……私がどのようにデバッグしたかも記しておきます:
まず、次のような小さなクラスを作成しました
# 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
次に、unicorn の after_fork フックでこのクラスを読み込み、ThreadDetective.start(14) を実行しました
このクラスは TracePoint を使用してスレッドが作成されるたびに厳密に監視し、スレッドに origin という名前の小さなフレームを追加して、どこから来たのかを追跡できるようにしました。多数のスレッドが観測されると、その情報を STDERR にダンプします。これは /var/www/discourse/logs/unicorn.stderr.log で確認できます。
100 個のスレッドがすべて単一の場所から発生していることがわかった時点で、根本原因を特定するのは非常に簡単でした。
eviltrout
(Robin Ward)
2019 年 9 月 12 日午後 5:13
14
Rails 6 の開発モードでは、dev.local をホスト名として使用できなくなったことに気づきました。そのため、そのホワイトリストを設定するための ENV 変数を追加しました:
committed 05:12PM - 12 Sep 19 UTC
Rails 6 seems to introduce a whitelist of allowed hosts. I personally
use `dev.l… ocal` for development and this no longer works.
This introduces a new ENV variable, `DISCOURSE_DEV_HOST`. If present,
it will whitelist that host for development mode.
sam
(Sam Saffron)
2019 年 9 月 15 日午後 10:03
15
このモンキーパッチを長期的に維持する必要はありません。Rails に修正がマージされたためです。
committed 03:11PM - 15 Sep 19 UTC
amotl
(Andreas Motl)
2020 年 1 月 7 日午前 12:27
16
こんにちは、
Discourse に Rails 6 を導入しようとするご尽力に感謝いたします。お手数ですが、これが Discourse に実装されるのはいつ頃と見込まれていますでしょうか?それとも、すでに 2.4.0.beta に含まれていますでしょうか?また、ユーザーのインスタンスにインストールされているプラグインが動作しなくなる可能性があるかどうかについてお伺いしています。
よろしくお願いいたします、
アンドレアス。
Falco
(Falco)
2020 年 1 月 7 日午前 12:34
17
デフォルトのリリースチャンネルを使用しているすべてのユーザー向けに、9 月からこの機能は公開されています。これは 2.4.0.beta5 で初めて紹介されました。
amotl
(Andreas Motl)
2020 年 1 月 7 日午前 1:38
18
わかりました、どうもありがとうございます。2020 年が素晴らしい年になりますようお祈りしております。ここでの皆さんの活動に心から感謝しています。