長文(約10万字)の投稿で大幅な編集を保存する際にDiffボトルネックによりバックエンドで502/504タイムアウトが発生

非常に長い投稿(約100,000文字)の編集と保存を行う際、バックエンドのタイムアウト問題が発生しました。保存操作中にサーバーが応答しなくなり、502/504エラーが発生します。フロントエンドのコンソールには以下のエラースタックが表示されます:

ajax-error.js:36:15
l ajax-error.js:36
u ajax-error.js:75
d ajax-error.js:84
Ember 41
update rest.js:72
update rest.js:72
save rest.js:115
editPost composer.js:1147
Ember 6

いくつかの比較テストを行ったところ、ボトルネックは旧バージョンと新バージョン間の差分計算にあることが示唆されました:

  • 長い投稿Aを直接編集して長い投稿Bにし、保存しようとすると、常に502/504タイムアウトが発生します。
  • まず長い投稿をクリアし、短いプレースホルダー(例:5文字)を保存してから、完全な新しいコンテンツBを貼り付けて保存すると、すぐに完了します。

現在の実装では、非常に長いテキストと変更率が高いという極端なケースにおいて、Diffエンジンが処理に苦労しているようです。パフォーマンス用のフォールバックメカニズムを追加することは可能でしょうか?例えば、テキストが非常に長く、変更率が高い場合、システムは詳細な行ごとのDiff計算を行うのではなく、「完全な書き換え」として扱うことができます。

チームには、大規模な投稿に対するDiff処理の最適化計画や、そのようなシナリオに対するグレースフルデグラデーション/保護機能の導入計画はありますか?もう一つのアイデアとしては、まず保存を成功させ、その後で非同期にDiffを計算するという方法があります。

その間、サーバー側のUnicornログにはタイムアウトの正確な時点が記録され、マークダウンの差分処理中にワーカーが終了したことが確認されました。

Unicorn worker received USR2 signal indicating it is about to timeout, dumping backtrace for main thread
config/unicorn.conf.rb:204:in `backtrace'
config/unicorn.conf.rb:204:in `block (2 levels) in reload'
/var/www/discourse/lib/discourse_diff.rb:172:in `[]'
/var/www/discourse/lib/discourse_diff.rb:172:in `tokenize_markdown'
/var/www/discourse/lib/discourse_diff.rb:115:in `side_by_side_markdown'
/var/www/discourse/app/serializers/post_revision_serializer.rb:128:in `body_changes'
... 

上記の問題は、UNICORN_TIMEOUT を 60 や 120 に変更することで解決できますか?

やあ、

これは Contribute > Bug に移動させようと思います。10 万文字は非常に珍しいですが、いずれにせよ、何らかのフォールバックを実装すべきだと思います。

2月に diff_too_complex: "差分が大きすぎて表示できません。個別に小さな編集をお試しください。" を追加しました。差分アルゴリズムは、複雑になりすぎると処理を停止する仕様です。

最新バージョンをお使いですか? 非常に非力なサーバーでない限り、これらのケースは処理できるはずです。

今年初の早期バージョンを使っていたのですが、ついに最新バージョンにアップグレードしました!

アップグレード後、「差分が表示されるには複雑すぎます」というメッセージを正常に表示させることに成功し、正直言って素晴らしいです。少なくともハードクラッシュすることなく、編集履歴の削除を続けることができます。

また、巨大な投稿を編集した際に発生していたフリーズやラグの問題も、おそらく修正されているようです。まだ完全に確信は持てませんが、最後のテストでは少しラグが発生したものの、幸いにも編集済みのバージョンは正常に処理されました。

今後さらにテストを行っていきます。ありがとうございます!

素晴らしい :+1:

「差分が複雑すぎ」という閾値は調整できると思うので、もし必要だと感じたら一緒に考えましょう :+1: (考慮すべき要素がたくさんあるので、万能な解決策があるとは限りませんが)

私はこれを何度もテストしました。**「差分の表示が複雑すぎてできません」**という通知をトリガーするほど複雑な編集を行っても、投稿が再び公開に失敗したことはありません。

この問題は最新バージョンで完全に解決したと確信しています。素晴らしい取り組みをしてくださったチームの皆様に改めて感謝申し上げます!