Flarum에서 Discourse로 25,000명 이상의 회원과 250,000개 이상의 게시물이 있는 포럼을 마이그레이션한 과정을 간단히 공유해 보려고 합니다.
이 글을 읽고 계신 분이라면 아실겠지만, Flarum → Discourse를 위한 공식 가져오기(import) 스크립트는 없습니다. 다만 @koen360 님이 호의적으로 FluxBB 가져오기 도구를 수정하여 사용자를 가져오는 방법을 공유해 주셨습니다. 그러나 우리 포럼의 성공은 게시글 내에서 매우 구체적인 용어를 검색하는 사용자들에게 크게 의존하고 있으므로, 게시물도 가져와야 했습니다. 그래서 그렇게 했죠… 실패한 마이그레이션 여러 시간, 두통, 그리고 몇 번의 고생 끝에 말이죠.
저는 마이그레이션 스크립트 작성 전문가라고 할 수는 없지만, 이 스크립트는 작성 시점의 Flarum 현재 버전(V0.1.0-beta.16)에서는 충분히 잘 작동합니다. 이 스크립트(아래 첨부)는 MySQL/MariaDB 데이터베이스에 접근할 수 있어야 하며, 문제가 발생했을 때 프로덕션 사이트를 망치지 않도록 데이터베이스의 복사본을 사용하는 것이 좋습니다. MySQL 연결 부분의 더미 값을 실제 값으로 교체하면 준비 완료입니다.
이 과정을 시작하기 전에 Flarum 데이터베이스 전체를 백업해 두십시오. 문제가 발생하면 되돌릴 수 없을 가능성이 높습니다.
Flarum → Discourse 마이그레이션에 도움이 필요하시면 이 스레드에 답글을 남겨 주세요. 저는 전문가가 아니지만, 가능한 한 도움을 드리겠습니다.
정말 좋습니다! 이 가져오기를 한 단계 더 발전시켜 주셔서 감사합니다! 시간이 지나면 태그, 아니 첨부파일이라도 포함할 수 있도록 확장되길 바랍니다.
태그 지원을 추가하는 데 얼마나 많은 작업이 필요할까요? vBulletin 5와 몇 가지 다른 시스템에서 작동 방식에 대한 참고 모델이 있을 것 같긴 하지만, Flarum에 맞게 얼마나 조정해야 할지는 전혀 감이 잡히지 않습니다. 어떤 통찰을 나눠 주셔도 감사하겠습니다. 그리고 실제로 해 봐야만 알 수 있는 부분이어서 답변이 어려우셔도 괜찮습니다.
현재 게시글이 비어 있고 기본 카테고리 3개만 있는 Discourse를 사용하고 있습니다.
Flarum에서 Discourse로 SQL을 가져오려고 시도했을 때 아래 오류가 발생했습니다.
su discourse -c 'bundle exec ruby script/import_scripts/flarum_import.rb'
Loading existing groups...
Loading existing users...
Loading existing categories...
Loading existing posts...
Loading existing topics...
creating users
13 / 13 (100.0%) [281 items/min] n]
importing top level categories...
39 / 39 (100.0%) [420 items/min] n]
importing children categories...
39 / 39 (100.0%) [290 items/min]
creating topics and posts
Traceback (most recent call last):
19: from script/import_scripts/flarum_import.rb:162:in `<main>'
18: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
17: from script/import_scripts/flarum_import.rb:32:in `execute'
16: from script/import_scripts/flarum_import.rb:101:in `import_posts'
15: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
14: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
13: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
12: from script/import_scripts/flarum_import.rb:122:in `block in import_posts'
11: from /var/www/discourse/script/import_scripts/base.rb:224:in `all_records_exist?'
10: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/transactions.rb:209:in `transaction'
9: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'
8: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
7: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
6: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
5: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
4: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
3: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
2: from /var/www/discourse/script/import_scripts/base.rb:231:in `block in all_records_exist?'
1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec': ERROR: duplicate key value violates unique constraint "import_ids_pkey" (PG::UniqueViolation)
DETAIL: Key (val)=(7) already exists.
20: from script/import_scripts/flarum_import.rb:162:in `<main>'
19: from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
18: from script/import_scripts/flarum_import.rb:32:in `execute'
17: from script/import_scripts/flarum_import.rb:101:in `import_posts'
16: from /var/www/discourse/script/import_scripts/base.rb:916:in `batches'
15: from /var/www/discourse/script/import_scripts/base.rb:916:in `loop'
14: from /var/www/discourse/script/import_scripts/base.rb:917:in `block in batches'
13: from script/import_scripts/flarum_import.rb:122:in `block in import_posts'
12: from /var/www/discourse/script/import_scripts/base.rb:224:in `all_records_exist?'
11: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/transactions.rb:209:in `transaction'
10: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'
9: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
8: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
7: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
6: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
5: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
4: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-7.0.3/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
3: from /var/www/discourse/script/import_scripts/base.rb:243:in `block in all_records_exist?'
2: from /var/www/discourse/script/import_scripts/base.rb:243:in `ensure in block in all_records_exist?'
1: from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec': ERROR: current transaction is aborted, commands ignored until end of transaction block (PG::InFailedSqlTransaction)
root@raspberrypi-app:/var/www/discourse# rake db:validate_indexes
Starting postgres on port: 11000
Waiting for PG server to start...
PG server is ready and DB is loaded
Running migrations on blank database!
Testing indexes on the default database
No missing indexes
No extra indexes
ubuntu@ip-172-26-1-78:~/discourse$ bundle exec ruby script/import_scripts/flarum_import.rb
Loading existing groups...
Loading existing users...
Loading existing categories...
Loading existing posts...
Loading existing topics...
creating users
Skipping 1000 already imported users
Skipping 826 already imported users
importing top level categories...
34 / 34 (100.0%) [5728165 items/min]
importing children categories...
34 / 34 (100.0%) [3194 items/min]
creating topics and posts
Traceback (most recent call last):
19: from script/import_scripts/flarum_import.rb:162:in `<main>'
18: from /home/ubuntu/discourse/script/import_scripts/base.rb:47:in `perform'
17: from script/import_scripts/flarum_import.rb:32:in `execute'
16: from script/import_scripts/flarum_import.rb:101:in `import_posts'
15: from /home/ubuntu/discourse/script/import_scripts/base.rb:916:in `batches'
14: from /home/ubuntu/discourse/script/import_scripts/base.rb:916:in `loop'
13: from /home/ubuntu/discourse/script/import_scripts/base.rb:917:in `block in batches'
12: from script/import_scripts/flarum_import.rb:122:in `block in import_posts'
11: from /home/ubuntu/discourse/script/import_scripts/base.rb:224:in `all_records_exist?'
10: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/transactions.rb:209:in `transaction'
9: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'
8: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
7: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
6: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
5: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
4: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
3: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
2: from /home/ubuntu/discourse/script/import_scripts/base.rb:231:in `block in all_records_exist?'
1: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec'
/home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec': ERROR: duplicate key value violates unique constraint "import_ids_pkey" (PG::UniqueViolation)
DETAIL: Key (val)=(53) already exists.
20: from script/import_scripts/flarum_import.rb:162:in `<main>'
19: from /home/ubuntu/discourse/script/import_scripts/base.rb:47:in `perform'
18: from script/import_scripts/flarum_import.rb:32:in `execute'
17: from script/import_scripts/flarum_import.rb:101:in `import_posts'
16: from /home/ubuntu/discourse/script/import_scripts/base.rb:916:in `batches'
15: from /home/ubuntu/discourse/script/import_scripts/base.rb:916:in `loop'
14: from /home/ubuntu/discourse/script/import_scripts/base.rb:917:in `block in batches'
13: from script/import_scripts/flarum_import.rb:122:in `block in import_posts'
12: from /home/ubuntu/discourse/script/import_scripts/base.rb:224:in `all_records_exist?'
11: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/transactions.rb:209:in `transaction'
10: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'
9: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
8: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
7: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
6: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
5: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activesupport-7.0.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
4: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/activerecord-7.0.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
3: from /home/ubuntu/discourse/script/import_scripts/base.rb:243:in `block in all_records_exist?'
2: from /home/ubuntu/discourse/script/import_scripts/base.rb:243:in `ensure in block in all_records_exist?'
1: from /home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec'
/home/ubuntu/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/rack-mini-profiler-3.0.0/lib/patches/db/pg.rb:56:in `exec': ERROR: current transaction is aborted, commands ignored until end of transaction block (PG::InFailedSqlTransaction)