Sto attualmente creando un plugin relativo a meritmoot.com (che è in sviluppo e utilizza rilasci rolling) e, a causa dell’utilizzo di dati esterni, sto impiegando un job Sidekiq di lunga durata. Purtroppo, per qualche motivo, il job continua a riavviare il codice interno senza fallire né fornire output di errore. C’è qualcosa che sto trascurando in Sidekiq che potrebbe causare questo riavvio?
Nel mio ultimo job (che dovrebbe essere eseguito solo una volta al giorno) relativo ai Roll Calls, il job è stato riavviato a questi intervalli senza alcun errore:
0h-58m-42s (orario di avvio della prima iterazione)
1h-30m-12s (primo riavvio)
2h-1m-1s (secondo riavvio)
3h-46m-49s
4h-17m-11s
4h-47m-33s
Il job non è terminato e tutto il progresso è stato ripristinato dall’inizio. Vale la pena notare che ho un mio processo di logging che reindirizza stderr e stdout per il mio codice interno, anche se dubito che possa interferire con Sidekiq. (Chiedimi pure se vuoi dargli un’occhiata, è molto utile per lo sviluppo!)
Potrei salvare il progresso effettuato all’interno del codice, ma preferirei un processo più semplice, poiché ciò creerebbe un sovraccarico. C’è qualcosa che sto trascurando in Sidekiq che potrebbe causare il riavvio del mio codice?
Memoria intesa come memoria del database o dell’hard disk? Ne sto usando molta, sì. Al momento sto valutando una versione leggermente modificata del suggerimento di @pfaffman, in cui forko il processo, permettendo al thread principale di terminare, ma generando un processo figlio che mantiene lo stesso contesto. (essenzialmente uno script esterno rispetto a Sidekiq)
Invece di fare così, perché non impostare il tuo lavoro per operare in piccoli lotti? Ha davvero bisogno di richiedere 4 ore? Sincronizza 10 argomenti, poi altri 10… e così via.
Sidekiq non ha nulla che possa terminare i job a esecuzione prolungata; le ricostruzioni dell’applicazione lo faranno, così come gli aggiornamenti tramite l’interfaccia web.
Alla fine ho rimosso il codice del processo, non era efficace. Il job di riavvio stava semplicemente nascondendo un problema di fondo: l’inefficienza . Invece, ho adottato questo approccio:
Scrivere codice SQL in bulk (molto più veloce dell’esecuzione sequenziale), rilevando quando è realmente necessario aggiornare e permettendomi di evitare di usare la classe PostRevisor per rieseguire l’aggiornamento su elementi che non sono cambiati
Aumentare l’efficienza nel recupero dei dati via HTTP utilizzando connessioni persistenti e altri punti dati, inclusi elementi compressi (ove possibile)
Ho scoperto che scrivere comandi SQL in bulk offre un enorme aumento di velocità. Ciò che sto aggiornando è:
La mia prossima idea è saltare completamente PostRevisor facendo qualcosa del genere:
1 - spostare i dati in una tabella temporanea
2 - UPDATE topics FROM temp_table
SET topics.title = temp_table.title, topics.last_updated = temp_table.last_updated
WHERE topics.id = temp_table.id AND topics.title != temp_table.title
3 - UPDATE posts FROM temp_table
SET posts.raw = temp_table.raw, posts.last_updated = temp_table.last_updated
WHERE posts.id = temp_table.id AND posts.raw != temp_table.raw
4 - e quindi attivare il job di re-indicizzazione della ricerca poiché titolo e contenuto sono cambiati.
C’è qualcosa che sto trascurando? Discourse è complesso, e saltando PostRevisor ho la sensazione di poter toccare tabelle con cui non ho esperienza (post_stats, post_timings, post_uploads, quoted_posts sono alcune che vedo nel database). Tuttavia, non ho bisogno di tutta la validazione che PostRevisor fornisce, dato che il sistema riceve queste revisioni da una fonte attendibile e prevedibile. Sembra una soluzione piuttosto incerta.
Aggiornamento: stavo eseguendo dei controlli sul codice poiché c’era un numero insolito di aggiornamenti nel tempo e ho scoperto che c’è qualcosa che causa aggiornamenti non necessari su elementi di dati che in realtà non sono cambiati nel loro formato JSON grezzo. Una volta risolto questo errore, quanto sopra probabilmente non sarà più necessario avrei dovuto fare i test… mi avrebbe fatto risparmiare un sacco di tempo. Penso che potrei comunque provare quanto sopra, anche se non sarà una priorità. Mi aiuterà per aggiornamenti rapidi quando modifico il formato in cui i dati vengono presentati. Inoltre è già scritto, solo non testato.
Ho completato il codice per l’aggiornamento in blocco: saresti interessato a vederlo spinto su un ramo specifico una volta che sarà più stabile? Il suo caso d’uso è piuttosto specifico, ma per ciò che fa può aggiornare migliaia di record rapidamente, inclusi i tag. È progettato per estendere TopicsBulkAction. Ecco il readme che ho scritto se desideri informazioni più approfondite:
# input
# - lista di hash contenenti cooked, post_id, topic_id, title, updated_at, tags (raw punterà a cooked)
# [{post_id: #, cooked: "", topic_id: #, title: "", updated_at: date_time, tags: [{tag: "", tagGroup: ""}, ... ] } , ... ]
# - category_name, il nome della categoria che viene aggiornata. Questo viene utilizzato per l'indicizzazione della ricerca.
# attributi hash opzionali da includere negli elementi della lista:
# - raw, se non incluso sarà uguale a cooked.
# - fancy_title, se non incluso sarà uguale a title
# - slug, se non incluso verrà elaborato da title (questo è correlato al suo URL)
# caso d'uso: aggiornamento regolare dei topic da una fonte dati backend non-Discourse in cambiamento, in modo efficiente
# per rispecchiare l'aggiornamento delle informazioni. Nota che questo non è pensato per la creazione generale di post o topic, ma per l'aggiornamento
# del titolo del topic e del post PRINCIPALE del topic. Per la revisione generale dei post, vai a PostRevisor in lib/post_revisor.rb
# - Assume contenuto già cotto (cooked), custom cooked o visualizzato così com'è. I dati non sono validati.
# - i post dovrebbero avere (cook_methods: Post.cook_methods[:raw_html]) impostato alla creazione se il tuo raw == cooked.
# Dovresti farlo se stai scrivendo HTML personalizzato da visualizzare all'interno del post.
# Altrimenti Discourse potrebbe ricucirlo in futuro, il che sarebbe negativo. Assicurati che la fonte delle informazioni
# sia attendibile e che i contenuti siano escapati.
# - Se quanto sopra non è ideale, assicurati di includere raw, imposta il metodo di cottura corretto durante la creazione del post
# (nel caso in cui il sistema lo ricucisca), esegui raw attraverso il metodo di cottura scelto e includi sia raw che il cooked risultante
# nei tuoi hash.
# - Tiene traccia della word_count annotando le differenze tra il conteggio delle parole prima e dopo del post e passando tale valore
# al topic.
# - Tiene traccia del conteggio dei tag in modo simile