Timeout 502/504 in Backend durante il salvataggio di modifiche importanti a post lunghi (~100k parole) a causa del collo di bottiglia di Diff

Durante la modifica e il salvataggio di post estremamente lunghi (circa 100.000 caratteri), abbiamo riscontrato un problema di timeout del backend. Il server diventa non rispondente durante l’operazione di salvataggio, generando errori 502/504. La console del frontend mostra il seguente stack di errori:

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

Ho eseguito alcuni test comparativi che suggeriscono che il collo di bottiglia si trova nel calcolo della differenza tra le versioni vecchia e nuova:

  • Modificare direttamente un lungo post A in un lungo post B e salvarlo innesca costantemente un timeout 502/504.
  • Cancellare innanzitutto il post lungo, salvare un segnaposto breve (ad esempio 5 caratteri), quindi incollare il contenuto nuovo completo B e salvarlo si completa rapidamente.

Sembra che il motore Diff attuale faticasse nei casi estremi che coinvolgono testo molto lungo combinato con un’elevata percentuale di modifiche. Sarebbe possibile aggiungere un meccanismo di fallback per le prestazioni? Ad esempio, quando il testo è estremamente lungo e il rapporto di modifica è elevato, il sistema potrebbe trattarlo come una “Riscrittura Completa” invece di eseguire un diff dettagliato riga per riga.

Il team ha in programma di ottimizzare la gestione del Diff per i post di grandi dimensioni, o di introdurre una sorta di degradazione graduale / protezione per tali scenari? Un’altra idea è consentire il salvataggio con successo prima, e calcolare il diff in modo asincrono in seguito.

2 Mi Piace

Nel frattempo, i log server-side di Unicorn hanno catturato il punto esatto del timeout, confermando che il worker è stato ucciso durante l’elaborazione della differenza del markdown:

Il worker di Unicorn ha ricevuto il segnale USR2 che indica che sta per scadere, dump del backtrace per il thread principale
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'
... 

Posso risolvere il problema sopra indicato modificando UNICORN_TIMEOUT a 60 o 120?

Ehi,

Penso che sposterò questa discussione in Contribute > Bug. 100k caratteri è molto insolito, ma indipendentemente da ciò, penso che dovrebbe essere implementato un qualche tipo di fallback.

A febbraio ho aggiunto diff_too_complex: "La differenza è troppo complessa da visualizzare. Prova a visualizzare le singole modifiche più piccole.". Il nostro algoritmo di differenza si fermerà semplicemente se la situazione diventa troppo complicata.

Stai utilizzando l’ultima versione qui? Dovrebbe gestire questi casi, a meno che tu non abbia un server con risorse estremamente limitate.

Ho già provato la versione iniziale di quest’anno, ma ho appena effettuato l’aggiornamento all’ultima versione disponibile!

Dopo l’aggiornamento, sono riuscito a visualizzare correttamente il messaggio «La differenza è troppo complessa per essere visualizzata» e, onestamente, è fantastico. Almeno non si blocca in modo critico e mi permette comunque di procedere con l’eliminazione della cronologia delle modifiche.

Sembra inoltre che il problema di congelamento/lentezza durante la modifica di post molto lunghi possa essere stato risolto. Non ne sono ancora del tutto certo, ma durante il mio ultimo test la lentezza è durata solo un attimo e, per fortuna, la versione modificata è stata elaborata con successo.

Continuerò a fare ulteriori test. Grazie mille!