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 не справляется с экстремальными случаями, когда очень длинный текст сопровождается высокой долей изменений. Не могли бы вы добавить механизм снижения производительности (fallback)? Например, когда текст очень длинный и процент изменений высок, система могла бы рассматривать это как «Полное переписывание», вместо того чтобы выполнять детальный посимвольный или построчный diff.

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

Тем временем серверные логи Unicorn зафиксировали точный момент тайм-аута, подтвердив, что воркер был убит во время обработки diff-а в формате 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'
... 

Можно ли решить указанную проблему, изменив значение UNICORN_TIMEOUT на 60 или 120?

Привет,

Думаю, я перенесу это в Contribute > Bug. 100 тысяч символов — это очень необычно, но в любом случае, я считаю, что следует реализовать механизм отката.

В феврале я добавил diff_too_complex: "Дифф слишком сложен для отображения. Пожалуйста, попробуйте просматривать отдельные небольшие изменения.". Наш алгоритм сравнения просто останавливается, если всё становится слишком запутанным.

Вы используете последнюю версию? Она должна справляться с такими случаями, если только у вас не очень слабый сервер.

Ранее я пользовался ранней версией этого года, но только что обновился до самой последней версии!

После обновления мне удалось увидеть сообщение «Различия слишком сложны для отображения», и, честно говоря, это отлично. По крайней мере, программа больше не вылетает с ошибкой и позволяет мне продолжить удаление истории редактирований.

Кажется, проблема с зависанием/задержками при редактировании больших постов также решена. Я пока не уверен на все сто, но во время последнего теста программа слегка подвисла, но затем, к счастью, успешно обработала отредактированную версию.

Я проведу дополнительное тестирование. Большое спасибо!

Потрясающе :+1:

Я считаю, что порог «слишком сложного diff» можно настроить, так что если вы считаете это необходимым, мы можем разобраться :+1: (учитывается множество факторов, поэтому универсального решения может не существовать)

Я уже несколько раз это проверял. Даже при редактировании, достаточно сложном для появления уведомления «Разница слишком сложна для отображения», пост никогда не срывался при публикации.

Я считаю, что эта проблема полностью решена в последней версии. Ещё раз спасибо команде за отличную работу!