将一个Discourse数据库克隆到另一个数据库会导致迁移时重建失败

你好。

我有两个 Discourse 实例,暂且称之为 Beta 和 Dev。Beta 比 Dev 更“正确”,因为它拥有我们最终想要的设置和初始数据。Dev 则是我们用来测试插件和主题的环境。

现在,我想克隆 Beta 的数据库供 Dev 实例使用,这样我们就能在不改动 Beta 的情况下,预览插件和主题的更改效果。但在克隆数据库并将 app.yml 指向新数据库后,迁移失败了。我的操作步骤如下:

  1. 生成 Beta 数据库的 backup.sql 备份(为了加快速度,排除了 user_histories、stylesheet_cache 和 scheduler_stats 表)。
  2. 创建新的 Dev 数据库。
  3. 将 backup.sql 恢复到新的 Dev 数据库中。
  4. 将 app.yml 指向新的 Dev 数据库并运行 rebuild。

以下是报错日志:

原因:
PG::SyntaxError: ERROR:  zero-length delimited identifier at or near """"
LINE 1: ...ECT 1 AS one FROM "categories" WHERE "categories"" = 1 LIM...
                                                             ^
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-2.2.0/lib/patches/db/pg.rb:69:in `exec_params'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rack-mini-profiler-2.2.0/lib/patches/db/pg.rb:69:in `exec_params'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/postgresql_adapter.rb:675:in `block (2 levels) in exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/postgresql_adapter.rb:674:in `block in exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract_adapter.rb:722:in `block (2 levels) in log'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract_adapter.rb:721:in `block in log'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract_adapter.rb:712:in `log'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/postgresql_adapter.rb:673:in `exec_no_cache'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/postgresql_adapter.rb:654:in `execute_and_clear'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/postgresql/database_statements.rb:98:in `exec_query'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/database_statements.rb:489:in `select'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/database_statements.rb:70:in `select_all'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/query_cache.rb:107:in `select_all'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/database_statements.rb:77:in `select_one'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/relation/finder_methods.rb:317:in `block in exists?'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/relation.rb:839:in `skip_query_cache_if_necessary'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/relation/finder_methods.rb:317:in `exists?'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/querying.rb:21:in `exists?'
/var/www/discourse/lib/seed_data/categories.rb:132:in `should_create_category?'
/var/www/discourse/lib/seed_data/categories.rb:102:in `create_category'
/var/www/discourse/lib/seed_data/categories.rb:15:in `block (2 levels) in create'
/var/www/discourse/lib/seed_data/categories.rb:15:in `each'
/var/www/discourse/lib/seed_data/categories.rb:15:in `block in create'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/i18n-1.8.5/lib/i18n.rb:313:in `with_locale'
/var/www/discourse/lib/seed_data/categories.rb:14:in `create'
(eval):6:in `block (2 levels) in run_file'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:46:in `eval'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:46:in `block (2 levels) in run_file'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:58:in `block in open'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:57:in `open'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:57:in `open'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:36:in `block in run_file'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/database_statements.rb:280:in `block in transaction'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/transaction.rb:280:in `block in within_new_transaction'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/transaction.rb:278:in `within_new_transaction'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/connection_adapters/abstract/database_statements.rb:280:in `transaction'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/transactions.rb:212:in `transaction'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:35:in `run_file'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:26:in `block in run'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:25:in `each'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu/runner.rb:25:in `run'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/seed-fu-2.3.9/lib/seed-fu.rb:29:in `seed'
/var/www/discourse/lib/tasks/db.rake:222:in `block in <main>'
/var/www/discourse/vendor/bundle/ruby/2.7.0/gems/rake-13.0.1/exe/rake:27:in `<top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => db:migrate

我意识到完整克隆可能会有问题,但您能分析一下问题可能出在哪里吗?另外,我这样做是不是太“新手”了?是否有其他工具或流程更适合用来克隆 Discourse 实例?

谢谢。

这两个实例是否运行相同版本的 Discourse?

如果您直接使用内置的备份和还原功能,操作会简单得多。只需确保您要还原到的网站版本至少与进行备份的网站版本一样新。

就是这样。正确的方法。感谢教育我这个新手。

很高兴能帮上忙!学习新的做事方式确实不容易。我经常会说:“哦,他们居然想到了这一点!”

如果两个站点共用同一个 S3 存储桶来存放 v 备份,那么您就不需要在站点之间传输备份了!您也可以通过命令行执行备份和恢复操作(有一个相关主题讨论了这一点)。