Backend 502/504 Timeout при сохранении крупных правок в длинных постах (~100k слов) из-за узкого места в Diff

При редактировании и сохранении очень длинных сообщений (около 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

Мы провели ряд сравнительных тестов, которые указывают на то, что узким местом является вычисление разницы (diff) между старой и новой версиями:

  • Прямое редактирование длинного сообщения A в длинное сообщение B и последующее сохранение стабильно вызывает тайм-аут с ошибкой 502/504.
  • Очистка длинного сообщения, сохранение короткого временного текста (например, 5 символов), затем вставка полного нового содержимого B и сохранение выполняются быстро.

Похоже, что текущий механизм вычисления разницы (Diff engine) не справляется с экстремальными случаями, когда очень длинный текст сопровождается высоким процентом изменений. Не могли бы вы добавить механизм снижения производительности (fallback)? Например, если текст очень длинный и доля изменений высока, система могла бы рассматривать это как «Полное переписывание» вместо детального поблочного сравнения.

Есть ли у команды планы по оптимизации обработки Diff для больших сообщений или внедрению механизма плавного снижения функциональности (graceful degradation) / защиты для таких сценариев? Еще одна идея: разрешать сначала успешное сохранение, а вычисление разницы выполнять асинхронно после этого.

Тем временем логи Unicorn на стороне сервера зафиксировали точный момент тайм-аута, подтвердив, что воркер был убит во время обработки markdown-разницы:

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'
...