Oggi ho provato ad aggiornare la mia installazione di Discourse, da 2.9.0.beta9 a 2.9.0.beta10. Ma è andato terribilmente storto.
Il mio primo tentativo è stato sulla console
cd /var/discourse
sudo git pull
sudo ./launcher rebuild app
Questo alla fine si è interrotto, con il seguente messaggio da qualche parte nel mezzo di tutti i log
PG::InvalidParameterValue: ERROR: cannot extract elements from a scalar
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:110:in `exec'
Sono stato in grado di ripristinare semplicemente il forum avviando la vecchia immagine (che era ancora in giro).
Il mio secondo tentativo è stato tramite la console web (/admin/upgrade). Ma alla fine si è bloccato con lo stesso tipo di errore: ERROR: cannot extract elements from a scalar. Tornando al pannello di aggiornamento, mi ha detto che tutti i componenti erano stati aggiornati correttamente. Ma dopo un riavvio del container, il server ha ora lanciato un errore HTTP 500
Ho fatto un’installazione pulita su una macchina separata, partendo da zero. Sono stato in grado di installare la versione beta10, ma il tentativo di ripristinare da un backup ha causato esattamente lo stesso errore!
INSERT INTO question_answer_votes (post_id, user_id, created_at)
SELECT
X.post_id AS post_id,
(X.value->>'user_id')::int AS user_id,
(X.value->>'created_at')::timestamp AS created_at
FROM (
SELECT
post_id,
jsonb_array_elements(value::jsonb) AS value
FROM post_custom_fields WHERE name = 'vote_history'
) AS X
WHERE (X.value->>'action') != 'destroy'
ORDER BY (X.value->>'created_at')::timestamp DESC
ON CONFLICT DO NOTHING
Se ho capito bene, questo accade perché la funzione psql jsonb_array_elements si aspetta un array, ma riceve un valore NULL.
Il sito che ho visto aveva un sacco di quei Post Custom Fields che contenevano un sacco di stringhe codificate più volte in modo da renderle inutilizzabili.
Alcune soluzioni, in ordine di complessità:
smettere di usare il plugin (e forse passare ai nuovi up vote)
eliminarli tutti
eliminare quelli non validi
modificare quei campi per trasformare nuovamente i dati in stringhe json valide.
Il sito che ho visto aveva dati non validi vecchi di anni. Sembra essere un bug esistente da anni che solo ora viene scoperto.
Potrebbe essere possibile scrivere codice per correggere le stringhe json corrotte, ma non sono riuscito a capire come farlo in 10 minuti.
Ci avevo pensato anch’io, ma una rapida verifica con il fork di Angus, non sembra che siano state eseguite migrazioni di dati. \u003chttps://github.com/angusmcleod/discourse-question-answer/compare/main…discourse:discourse-upvotes:main\u003e
Questo sembra una contaminazione dei dati dai vecchi post Q&A come hai detto. Trovo anche divertente che questo stia emergendo ora dato che quella migrazione è di novembre 2021 – immagino sia perché JayJay sta passando al nuovo plugin solo ora? In ogni caso, daremo un’altra occhiata a quella migrazione.
Se rimuovessi il plugin, il ripristino del backup causerebbe comunque l’esecuzione della query errata.
Quindi, dovrei rimuovere sia il plugin sia qualsiasi tabella + query utilizzata da questo plugin.
Come farei a conoscere le tabelle coinvolte?
Ci provo subito. Ho esaminato il file dump.sql, che fa parte del backup, e non c’è alcuna menzione di alcuna tabella question_answer_* . Quindi questo mi dà speranza…
I dati corrotti si trovano nella tabella PostCustmField. Ma se non si dispone del plugin, non tenterà di migrare tali dati nella nuova tabella.
Il problema non è la migrazione in sé, ma il fatto che a un certo punto nel passato i dati si siano corrotti. Si è rotto, ma si è rotto in un modo che è passato inosservato per anni. Penso che forse ogni nuovo voto positivo l’abbia corrotta ulteriormente. Una soluzione ragionevole potrebbe essere quella di ignorare i dati corrotti, magari contrassegnandoli come corrotti (forse rinominando il campo personalizzato) in modo che le future migrazioni possano ignorarli e qualcuno possa risolverli manualmente, se lo desidera.
Successo anche in live. Ho disabilitato il plugin e siamo ripartiti.
Mi chiedo ancora perché non abbia riscontrato questo problema prima. Come ho detto, ogni mese, come routine, aggiorniamo tutti i nostri sistemi, quindi avrei dovuto vedere questo problema prima.
Come potrei connettermi autonomamente al database di Discourse per verificare cosa c’è nella tabella post_custom_fields?
Il vecchio plugin QnA utilizzava il tipo di casting standard del campo personalizzato di Discourse, che serve a gestire il casting di quel campo in JSON. Ma in alcuni casi (come questo) semplicemente non funziona, motivo per cui (idealmente) è necessario implementare controlli di formato quando si lavora con campi personalizzati di Discourse (in particolare se si lavora con codice e dati piuttosto vecchi come questi). Suggerirei che è quello che il plugin Upvotes deve fare qui, da cui infatti proviene l’errore immediato.
Puoi utilizzare il plugin Data Explorer per verificare cosa hai lì.
Bene, mi fido principalmente di te su questo, e penso che siamo d’accordo. Penso che sia vero che la migrazione funziona se i dati non sono corrotti. Siamo d’accordo che se i dati sono corrotti dovrebbe fallire in modo più aggraziato di quanto non faccia ora.
Sì, ma i dati sono probabilmente stati corrotti anni fa (questo è il caso del sito che conosco bene), ma non te ne sei accorto perché non è fallito catastroficamente. Sono abbastanza sicuro che non stesse gestendo i voti come previsto, ma nessuno se ne è accorto.
Lo farei da rails, qualcosa del genere:
./launcher enter app
rails c
Poi cose come queste:
all_votes=PostCustomField.where(name: "vote_history")
likely_broken_votes=PostCustomField.where(name: "vote_history").where("value like '\\\"%'")
Guarda solo l’id e i dati:
all_votes.pluck(:id,:value)
Prendi solo un pcf:
pcf=PostCustomField.find(1234)
Correggilo
pcf.value='the stuff you really want in it'
pcf.save
Alcune persone hanno una versione molto vecchia del plugin “question answer” con il mio nome utente GitHub personale nell’URL del repository nel loro file app.yml.
Anni fa ho trasferito il plugin QnA a paviliondev. GitHub reindirizza gli URL dei repository quando vengono trasferiti, quindi i vecchi URL con il mio nome utente personale continuavano a funzionare.
Anni dopo, Pavilion ha trasferito il plugin Question Answer a Discourse. Inizialmente Discourse ha mantenuto il nome discourse-question-answer.
Pochi mesi fa ho creato un mio fork del plugin ospitato in discourse, mentre era ancora chiamato discourse-question-answer.
Le persone con collegamenti molto vecchi al plugin QnA con il mio account GitHub personale stavano ora clonando il mio nuovo fork del plugin discourse-question-answer significativamente aggiornato, ospitato in discourse. In altre parole, un link molto vecchio ora puntava a un fork di un nuovo plugin. Nonostante gli anni trascorsi, avrei dovuto prevederlo, quindi mi scuso per questo. Ho rimosso quel fork.
Discourse ha cambiato il nome di discourse-question-answer in discourse-upvotes. Questo cambio di nome non ha avuto un impatto materiale sul tuo caso @Jaap-Jan_Swijnenburg, ma è il motivo per cui ora stai (inaspettatamente) clonando un fork di quel repository.
Una migrazione in discourse/discourse-upvotes (ex discourse-question-answer) presuppone che la colonna value in post_custom_fields sia di tipo JSON.
I vecchi dati creati dal plugin quando era angusmcleod/discourse-question-answer (anni fa) non sono stati salvati come JSON valido dalla “concern” HasCustomFields in discourse/discourse. Sto ipotizzando, ma questi dati sono stati probabilmente aggiunti prima che il controllo del tipo JSON venisse aggiunto 4 anni fa (È ancora possibile che si verifichino JSON non validi nei campi personalizzati registrati come JSON in casi limite).
Pertanto
Quando le persone con l’URL (vecchio di anni) angusmcleod/discourse-question-answer nel loro app.yml aggiornano il loro Discourse, viene clonato il plugin della nuova versione, la migrazione viene eseguita e potenzialmente crea questo errore.
Ci sono alcune soluzioni a questo problema:
@Jaap-Jan_Swijnenburg nel tuo caso devi solo rimuovere il riferimento al mio vecchio plugin QnA e potrai ricostruire il tuo sito. Questo è tutto; niente di più. Sembra che tu l’abbia fatto
La migrazione del plugin discourse/discourse-upvotes potrebbe essere aggiornata per gestire valori non JSON nella colonna value in post_custom_fields.
Noterei che 2 gestirebbe anche il caso aggiuntivo di persone che desiderano effettivamente passare da una vecchia versione del plugin QnA a discourse-upvotes. In tal caso, la migrazione verrà eseguita e fallirà se una qualsiasi voce nella colonna value di post_custom_fields non è un JSON valido.