マルチサイトがアップロードを実際の DB 名ではなく「default」に復元する問題

Discourse の最新ベータ版、Docker 環境、マルチサイト構成での問題です。

元のデータベース REDACTED のバックアップを、現在のデータベース db8015 に復元しようとしています。アップロードファイルは、ファイルシステム上でもデータベース上でも default に保存されてしまいます。

この問題は、GUI から復元を実行した場合も、RAILS_DB=db8015 RAILS_ENV=production script/discourse restore コマンドでコマンドラインから復元を実行した場合も発生します。

復元処理中に、RailsMultisite::ConnectionManagement.current_db が正しいデータベースから default に変更されてしまいます。これは [Rake::Task['db:_dump'].invoke in db.rake](https://github.com/discourse/discourse/blame/master/lib/tasks/db.rake#L59) の行に起因することを特定できました。

その行の前では RailsMultisite::ConnectionManagement.current_db は正しい値(db8015)を持っていましたが、その行の後では default になっています。

どうやら この修正 が何らかの原因で本番環境を壊してしまったようです @sam?

ログ:

[STARTED]
'DHSupport' has started the restore!
Marking restore as running...
Making sure /var/www/discourse/tmp/restores/db8015/2019-10-11-104940 exists...
Copying archive to tmp directory...
Unzipping archive, this may take a while...
No metadata file to extract.
Validating metadata...
  Current version: 20191007140446
  Restored version: 20190908234054
Extracting dump file...
Creating missing functions in the discourse_functions schema
Cannot restore into different schema, restoring in-place
Enabling readonly mode...
Pausing sidekiq...

[関連しない部分を多数削除]

Clear theme cache
Extracting uploads...
Remapping uploads...
Remapping 'uploads/REDACTED' to 'uploads/default'
Optimizing site icons...
Posts will be rebaked by a background job in sidekiq. You will see missing images until that has completed.
You can expedite the process by manually running "rake posts:rebake_uncooked_posts"
Executing the after_restore_hook...
Cleaning stuff up...
Dropping function from the discourse_functions schema
Removing tmp '/var/www/discourse/tmp/restores/db8015/2019-10-11-104940' directory...
Unpausing sidekiq...
Marking restore as finished...

これはいまだに問題ですか、@sam

確認のため、再現手順は以下の通りです。

  • Docker コンテナ内でマルチサイトを作成

  • そのマルチサイトの 1 つをバックアップ

  • 新しい Docker コンテナでそれをリストア

  • アップロードされたファイルが誤った場所にある

@kris.kotlarek さん、ローカル環境でこの現象を再現し、修正可能か確認していただけますか?

将来的にこの問題に直面する可能性が高いと懸念しています。

この問題を再現するには、宛先コンテナのみをマルチサイトにする必要があります。

  • Docker コンテナ内にフォーラムを作成
  • バックアップを作成
  • 新しいマルチサイト Docker コンテナでそれを復元
  • アップロード先が正しくない

このバグについて時間を費やしましたので、私の調査結果をお伝えします。基本的には、あなたが既におっしゃっていたことをすべて確認しました。復元プロセスは以下の通りです:

migrate_database
reconnect_database
...
extract_uploads

問題は、マイグレーションタスクの後に reconnect_database が意図したデータベースに切り替わらず、デフォルトのものに対して動作を始めてしまうことです。

したがって、このコードは誤っています:

def extract_uploads
  ...
  current_db_name = 
  RailsMultisite::ConnectionManagement.current_db # default
  optimized_images_exist = File.exist?(File.join(tmp_uploads_path, 'optimized'))

応急処置的な解決策として、ここでは正しい名前を保持している @current_dbRailsMultisite::ConnectionManagement.current_db の代わりに使用することも考えられますが、これでは reconnect_database が正しく機能しない根本的な原因は解決されません。

問題の究明のため、さらに詳しく調査する必要があります。

本当に、その現象はマイグレーションタスクのに発生しているのですか?

このコード

  migrate_database
  puts "マイグレーション後、再接続前 #{RailsMultisite::ConnectionManagement.current_db}"
  reconnect_database

は以下のように出力されます

サイトアイコンの最適化中... 完了
マイグレーション後、再接続前 default
データベースに再接続中...

しかし、lib/tasks/db.rake 内の以下の行をコメントアウトすると

Rake::Task['db:_dump'].invoke

以下のように出力されます

サイトアイコンの最適化中... 完了
マイグレーション後、再接続前 db8015
データベースに再接続中...

おっしゃる通りです。restorer.rb から Rake::Task["db:migrate"].invoke を削除したところ、プロセス全体で正しいデータベースが取得できました。
あなたは私より一歩先を行いていますね。今の計画は、migrate タスクに入って、どのステップがプロセスを破綻させているかを確認することです。
_dump についてご指摘いただきありがとうございます。すぐにそこへ移動して、内部で何が起きているかを確認します。

少し調査しましたが、ついに修正を見つけました :slight_smile:

ありがとうございます!

もう少し考えてみたのですが、db:dump がプライマリデータベース以外のものに対して実行された場合、いったい何を意味するのでしょうか?

データベースがデフォルトでない場合は、db:dump コマンドをスキップするべきではないでしょうか?

修正がマージされました。問題の発見ありがとうございます。そのダンプコマンドは、マルチサイト移行に問題があったために追加されました。すべてのマルチサイトは同じ構造を持つべきであるため、構造をダンプする際にどのデータベースを使用しても問題ないと思います。