Migrazione database vBulletin 5 - Errori script di importazione

Ok, ricapitoliamo velocemente.

Sto facendo volontariato per la migrazione di un forum che attualmente è su vbulletin3.
Su un ambiente di staging, partendo da un dump del database (20GB, avete letto bene).

Eseguo l’aggiornamento a vBulletin 5. Ci sono volute 5-6 ore ma è andato a buon fine. La versione è vBulletin 5.4.
Ho fatto un po’ di pulizia dei nomi utente per farli accettare da discourse.

Ora, ho installato discourse su docker e ho seguito in modo approssimativo questa guida per la preparazione. Approssimativamente significa che la maggior parte era ridondante o obsoleta, ma ha aiutato a farsi un’idea di cosa fare.

Sono arrivato al punto in cui sto letteralmente diventando cieco perché ho quasi zero esperienza di programmazione Ruby.
Quindi, le parti rilevanti, dopo aver terminato l’installazione sono entrato nel container con ./launcher enter app quindi:

  • Aggiunto freetds-dev e libmariadb-dev
  • Modificato il Gemfile per aggiungere la gem php_serialize.
  • Dalla shell, eseguito export IMPORT=1 per impostare l’ambiente per l’importazione.
  • Come utente discourse eseguito bundle install --no-deployment --without test --without development --path vendor/bundle

Ho ottenuto l’errore:

You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
updated Gemfile.lock to version control.

If this is a development machine, remove the /var/www/discourse/Gemfile freeze
by running `bundle config unset deployment`.

The list of sources changed
The dependencies in your gemfile changed

You have added to the Gemfile:
* mysql2
* redcarpet
* php_serialize
* sqlite3 (~> 1.3, >= 1.3.13)
* ruby-bbcode-to-md
* reverse_markdown
* tiny_tds
* csv
* parallel

Quindi, ho continuato con:

  • bundle config unset deployment e rieseguito il comando precedente.
  • Verificato che sia mysql2 che php_serialize fossero presenti (lo erano).
  • Aggiunto gli avatar del vecchio forum (nessun allegato da importare) e assegnato la proprietà delle directory all’utente discourse nella sua home /home/discourse.
  • Modificato script/import_scripts/vbulletin5.rb per cambiare il riferimento per la connessione al db.
  • Come utente discourse eseguito bundle exec ruby script/import_scripts/vbulletin5.rb

Questo mi ha restituito un errore relativo a tzinfo Integer values not supported che ho trovato menzionato qui su questo discourse.

Loading existing groups...
Loading existing users...
Loading existing categories...
Loading existing posts...
Loading existing topics...

importing groups...
       41 / 41 (100.0%)  [2294 items/min]
importing users
Traceback (most recent call last):
        15: from script/import_scripts/vbulletin5.rb:726:in `<main>'
        14: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
        13: from script/import_scripts/vbulletin5.rb:46:in `execute'
        12: from script/import_scripts/vbulletin5.rb:79:in `import_users'
        11: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
        10: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
         9: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
         8: from script/import_scripts/vbulletin5.rb:98:in `block in import_users'
         7: from /var/www/discourse/script/import_scripts/base.rb:264:in `create_users'
         6: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
         5: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
         4: from /var/www/discourse/script/import_scripts/base.rb:265:in `block in create_users'
         3: from script/import_scripts/vbulletin5.rb:110:in `block (2 levels) in import_users'
         2: from script/import_scripts/vbulletin5.rb:718:in `parse_timestamp'
         1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone.rb:575:in `utc_to_local'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/tzinfo-2.0.5/lib/tzinfo/timestamp.rb:138:in `for': Integer values are not supported (ArgumentError)

Il suggerimento di @Haddoq è stato di cambiare una riga da Time.zone.at(@tz.utc_to_local(timestamp)) in Time.zone.at(timestamp).

Ha anche suggerito di aggiungere lastvisit nella query dell’utente perché altrimenti causerà un altro errore, quindi l’ho fatto anche quello.

Tuttavia, ora quando avvio la migrazione con bundle exec ruby script/import_scripts/vbulletin5.rb ottengo questo:

Loading existing groups...
Loading existing users...
Loading existing categories...
Loading existing posts...
Loading existing topics...

importing groups...
       41 / 41 (100.0%)  [120217 items/min]
importing users
Traceback (most recent call last):
        13: from script/import_scripts/vbulletin5.rb:727:in `<main>'
        12: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
        11: from script/import_scripts/vbulletin5.rb:46:in `execute'
        10: from script/import_scripts/vbulletin5.rb:79:in `import_users'
         9: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
         8: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
         7: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
         6: from script/import_scripts/vbulletin5.rb:80:in `block in import_users'
         5: from script/import_scripts/vbulletin5.rb:723:in `mysql_query'
         4: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:22:in `query'
         3: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:147:in `query'
         2: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:147:in `handle_interrupt'
         1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `block in query'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query': You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'CASE WHEN u.scheme='blowfish:10' THEN token (Mysql2::Error)
                 WHEN u.scheme='lega' at line 2

A questo punto sono un po’ perso. Qualcuno può aiutarmi?

paging @Canapin dato che è stato in “Migration Vietnam” e potrebbe saperne di più :heart:

Lavorare per 8 ore di fila fa male.

Quando ho aggiunto u.lastvisit alla fine di SELECT u.userid, u.username, u.homepage, u.usertitle, u.usergroupid, u.joindate, u.email, ho dimenticato di aggiungere una virgola dopo.

Scusa Canapin per il ping :frowning:

1 Mi Piace

Va bene, problema di follow-up. La guida che stavo seguendo affermava che il processo di registrazione poteva essere riavviato se rallentava.

Ma quando riavviato ricevo errori riguardo a utenti già esistenti nel database postgres.

Sciocco da parte mia, sono andato e ho eliminato tutti gli utenti con id > 1 nel db (lasciando fondamentalmente discobot, system e admin) e ho riavviato. Ciò fa continuare l’importazione ma le email di tutti gli utenti creati in precedenza sono contrassegnate come “già utilizzate” da qualche parte.

Cosa posso fare per pulirlo e questo processo non dovrebbe invece saltare l’inserimento se esiste già un nome utente corrispondente?

Modifica: Va bene, ho scoperto che devo pulire users, email_tokens e user_emails.

1 Mi Piace

Purtroppo, non ho tenuto traccia di ciò che ho modificato nelle mie precedenti importazioni, quindi ho poca conoscenza. Ora ho un’istanza Discourse personale in cui scrivo questo tipo di cose… Avrei dovuto farlo prima!
Sono più esperto nelle importazioni quando ne sto effettivamente gestendo una.

Per quanto riguarda l’eliminazione degli utenti, potresti aver voluto usare UserDestroyer tramite la console rails:

2 Mi Piace

Ottimo, lo terrò a mente per la migrazione “reale”. Per ora sto solo facendo un test dell’intero processo mentre scrivo un runbook :slight_smile:

1 Mi Piace

Perché l’hai fatto? A meno che tu non abbia cambiato qualcosa nello script che importerebbe diversamente quegli utenti, dovresti semplicemente riavviare e farlo importare quelli che non ha ancora importato.

Se hai bisogno di ricominciare da capo, è molto più facile ripristinare un backup o eliminare e creare un nuovo database.

Dovrebbe trovare gli id di importazione nella tabella UserCustomFields. Non sono abbastanza sicuro di come potresti ottenere quell’errore.

Le modifiche sono quelle che ho elencato. Sono sorpreso quanto te, ma lo script non andava avanti e si bloccava semplicemente con un errore.

C’è un modo per velocizzare l’importazione?

Ho oltre 90.000 utenti in questa community e la velocità di importazione degrada nel tempo per qualche motivo e non riesco a immaginare perché.

È andato avanti tutta la notte e solo per gli utenti siamo a 25123 / 95635 ( 26.3%) [42 elementi/min]

Ci sono diversi ordini di grandezza in più di post. Quanto tempo dovrei aspettarmi che avvenga una migrazione? Giorni? settimane?

Quanta RAM? È probabile che sia quello il problema. Puoi interrompere e riavviare.

Ci ho messo settimane. Ecco perché esistono gli importatori in blocco.

Ha solo 2 GB di RAM. È una macchina di test. Potrei eseguirlo localmente invece che su una VM (16 GB di RAM sarebbero molto meglio?) e poi impacchettare tutto e caricarlo alla fine, immagino.

Puoi elaborare sui bulk importer? È la prima volta che ne sento parlare e sicuramente avrebbero dovuto apparire quando cercavo “migrare vbulletin a discourse” su Google :angry:

Frustrated Jason Segel GIF by NETFLIX

Posso eseguirlo anche se l’altro importatore ha già elaborato alcuni utenti o dovrei ripulire?

Ho provato, nel peggiore dei casi non funzionerà. Mi stanno arrivando spam con

ERROR: no implicit conversion of nil into String
/var/www/discourse/script/bulk_import/base.rb:861:in `encode'
/var/www/discourse/script/bulk_import/base.rb:861:in `normalize_charset'
/var/www/discourse/script/bulk_import/base.rb:856:in `normalize_text'
script/bulk_import/vbulletin5.rb:123:in `block in import_users'
/var/www/discourse/script/bulk_import/base.rb:725:in `block (2 levels) in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/script/bulk_import/base.rb:723:in `block in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/pg-1.4.5/lib/pg/connection.rb:196:in `copy_data'
/var/www/discourse/script/bulk_import/base.rb:722:in `create_records'
/var/www/discourse/script/bulk_import/base.rb:340:in `create_users'
script/bulk_import/vbulletin5.rb:120:in `import_users'
script/bulk_import/vbulletin5.rb:63:in `execute'
/var/www/discourse/script/bulk_import/base.rb:100:in `run'
script/bulk_import/vbulletin5.rb:781:in `<main>'

Presumo che dovrei ripulire utenti e gruppi che sono le uniche cose che l’altro importatore ha creato/iniziato a creare.

Prima di andare a pasticciare di nuovo nel database, c’è qualche comando ruby che posso eseguire che se ne occupi in modo pulito?

Per questa volta andrò avanti e distruggerò e ricreerò l’installazione di discourse. Grazie al cielo per Docker.

No, installazione pulita, lo script fallisce ancora con questo generico

ERROR: no implicit conversion of nil into String
/var/www/discourse/script/bulk_import/base.rb:861:in `encode'
/var/www/discourse/script/bulk_import/base.rb:861:in `normalize_charset'
/var/www/discourse/script/bulk_import/base.rb:856:in `normalize_text'
script/bulk_import/vbulletin5.rb:123:in `block in import_users'
/var/www/discourse/script/bulk_import/base.rb:725:in `block (2 levels) in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/script/bulk_import/base.rb:723:in `block in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/pg-1.4.5/lib/pg/connection.rb:196:in `copy_data'
/var/www/discourse/script/bulk_import/base.rb:722:in `create_records'
/var/www/discourse/script/bulk_import/base.rb:340:in `create_users'
script/bulk_import/vbulletin5.rb:120:in `import_users'
script/bulk_import/vbulletin5.rb:63:in `execute'
/var/www/discourse/script/bulk_import/base.rb:100:in `run'
script/bulk_import/vbulletin5.rb:781:in `<main>'

C’è un modo per eseguire il debug di questo problema in modo da poter almeno capire quale valore è nil e ci si aspetta che sia qualcos’altro?

Ok, l’errore sembra essere correlato alla codifica.
In bulk_import/vbulletin5.rb posso specificare la codifica (nel nostro caso, UTF8mb4 ma nel file base.rb non sembra mappare nulla nella mappa dei set di caratteri

Ciao!

Alcuni suggerimenti generali:

  1. Se apporti modifiche allo script, è generalmente consigliabile ricominciare da capo o almeno da un punto noto e funzionante. Puoi farlo più facilmente ripristinando un backup effettuato poco prima dell’esecuzione della migrazione, come ha detto @pfaffman.
  2. Gli importatori di massa generalmente richiedono molto meno tempo, ma questo in particolare ha il potenziale per consumare ENORMI quantità di RAM perché memorizza nella cache le cose in memoria. Per una particolare migrazione di vBulletin che ho eseguito da un file SQL di 2 GB non compresso, il processo ha richiesto 22 GB di RAM (ricontrollato, non è un errore di battitura).
  3. Se apporti modifiche allo script, ti suggerisco di creare una versione di test dell’input con, diciamo, 100 o 1000 record per ogni tabella (ma fai attenzione all’integrità referenziale, ovvero non troncare le tabelle referenziate da altre tabelle). Testare le modifiche con un processo di oltre 8 ore eroderà la tua sanità mentale molto rapidamente.

Un suggerimento più specifico riguardo agli stack trace: cerca le righe che menzionano il file specifico che hai eseguito. In questo caso, sì, è un problema di codifica, ma più rilevante è il fatto che riguarda i nomi utente:

Hai detto che hai dovuto sanificare i nomi utente, quindi ricontrollerei che li hai codificati come previsto dallo script.

2 Mi Piace

Puoi semplicemente eliminare, creare e migrare il database invece di ricreare Discourse. È un po’ complicato, però, poiché devi

  sv stop unicorn

e poi

  rake db:drop db:create db:migrate

Si lamenterà e ti dirà di impostare una variabile d’ambiente che devi inserire sulla riga prima del task rake.

Puoi anche ripristinare un backup, che può essere più conveniente.

A titolo informativo, non credo di aver mai usato uno script di migrazione di massa.

1 Mi Piace

È ancora più strano dato che gli username sono stati tutti sanificati per seguire le linee guida di Discourse, in pratica sono stati tutti modificati per essere solo lettere, numeri o _, niente altro.

In ogni caso, cambiare il charset da utf8mb4 a utf8 come era predefinito ha fatto sì che funzionasse, ma ora sto ricevendo errori per email non valide

ERROR: can't modify frozen String: "24ef401b30f5161e5a0bb27ec49ed921@email.invalid"
/var/www/discourse/script/bulk_import/base.rb:457:in `downcase!'
/var/www/discourse/script/bulk_import/base.rb:457:in `process_user_email'
/var/www/discourse/script/bulk_import/base.rb:726:in `block (2 levels) in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/mysql2/alias_method.rb:8:in `each'
/var/www/discourse/script/bulk_import/base.rb:723:in `block in create_records'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/pg-1.4.5/lib/pg/connection.rb:196:in `copy_data'
/var/www/discourse/script/bulk_import/base.rb:722:in `create_records'
/var/www/discourse/script/bulk_import/base.rb:351:in `create_user_emails'
script/bulk_import/vbulletin5.rb:151:in `import_user_emails'
script/bulk_import/vbulletin5.rb:66:in `execute'
/var/www/discourse/script/bulk_import/base.rb:100:in `run'
script/bulk_import/vbulletin5.rb:781:in `<main>'

Ora vado a scoprire di cosa si tratta dato che l’importazione “non di massa” stava rilevando alcune email malformate ma le stava sostituendo automaticamente.

Dopo averlo fatto, crea semplicemente un backup della tua installazione di Discourse vuota e incontaminata.
Puoi sempre ripristinarla molto rapidamente e ricominciare da capo.

2 Mi Piace

Inoltre, se hai problemi, ad esempio, con l’importazione dei post, potresti anche uscire dallo script dopo che l’importazione degli utenti è stata completata in modo soddisfacente e creare un altro backup. Quindi puoi riavviare lo script e riprendere dal momento in cui hai già importato gli utenti.

1 Mi Piace