Ошибка при миграции на внешний экземпляр PostgreSQL

Я настроил свой форум, используя discourse-docker с конфигурацией по умолчанию (самодостаточной). Мне нужно переключиться на использование отдельного сервера PostgreSQL.

Я создал резервную копию, затем изменил app.yml, пересобрал контейнер и попытался восстановить данные из резервной копии через CLI. Восстановление не удалось. Похоже, что при восстановлении использовался правильный хост для доступа к PostgreSQL, но применялся порт по умолчанию (5432), а не тот, который я настроил (9432).

Ошибка:

psql: error: connection to server at "[REDACTED HOST]" ([REDACTED IP]), port 5432 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
EXCEPTION: psql failed: 	Is the server running on that host and accepting TCP/IP connections?
/var/www/discourse/lib/backup_restore/database_restorer.rb:92:in `restore_dump'
/var/www/discourse/lib/backup_restore/database_restorer.rb:26:in `restore'
/var/www/discourse/lib/backup_restore/restorer.rb:51:in `run'
script/discourse:149:in `restore'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/thor-1.3.0/lib/thor/command.rb:28:in `run'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/thor-1.3.0/lib/thor/invocation.rb:127:in `invoke_command'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/thor-1.3.0/lib/thor.rb:527:in `dispatch'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/thor-1.3.0/lib/thor/base.rb:584:in `start'
script/discourse:290:in `<top (required)>'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/cli.rb:451:in `exec'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor/command.rb:28:in `run'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor.rb:527:in `dispatch'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/cli.rb:34:in `dispatch'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/vendor/thor/lib/thor/base.rb:584:in `start'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/cli.rb:28:in `start'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/exe/bundle:28:in `block in <top (required)>'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/usr/local/lib/ruby/gems/3.2.0/gems/bundler-2.5.3/exe/bundle:20:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Trying to rollback...
Rolling back...
Cleaning stuff up...
Dropping functions from the discourse_functions schema...
Removing tmp '/var/www/discourse/tmp/restores/default/2024-01-17-201724' directory...
Unpausing sidekiq...
Marking restore as finished...
Notifying 'system' of the end of the restore...
Finished!
[FAILED]

Конфигурация:
В файле app.yml, в разделе templates:, я закомментировал строку - "templates/postgres.template.yml".

Также я добавил следующее в раздел env:

  DISCOURSE_DB_USERNAME: [REDACTED]
  DISCOURSE_DB_PASSWORD: [REDACTED]
  DISCOURSE_DB_HOST:  [REDACTED]
  DISCOURSE_DB_PORT: 9432
  DISCOURSE_DB_NAME: [REDACTED]

При пересборке был создан новый пустой сайт? Если нет, то у вас где-то проблема.

Можете ли вы получить доступ к базе данных изнутри контейнера с помощью команды psql <некоторые флаги для указания базы данных>?

Если внутри контейнера выполнить set|grep DB, увидите ли вы свои переменные окружения?

Да, ко всем трём. Он создаёт новый пустой сайт, подключённый к правильной базе данных. Переменные окружения отображаются при поиске через grep, и я могу вручную подключиться к БД изнутри контейнера.

Существует небольшая вероятность того, что скрипт восстановления каким-то образом не учитывает переменные окружения (хотя всё остальное их учитывает?). Способы проверить это: посмотреть код и попробовать выполнить восстановление через интерфейс. Если восстановление через интерфейс работает, то, на мой взгляд, можно перенести эту тему в bug.

Я также пытался выполнить восстановление через интерфейс пользователя, но получил ту же ошибку.

Тогда, я думаю, следующим шагом будет просмотр кода.

Особенно странно, что для всего остального это работает.

Можете ли вы зайти в консоль Rails и показать нам следующие значения:

BackupRestore.database_configuration
BackupRestore::DatabaseRestorer.psql_command

например:

→ rails c
Загрузка среды разработки (Rails 7.0.8)
[1] pry(main)> BackupRestore.database_configuration
=> #<struct BackupRestore::DatabaseConfiguration
 host=nil,
 port=nil,
 username="michael",
 password=nil,
 database="discourse_development">

[2] pry(main)> BackupRestore::DatabaseRestorer.psql_command
=> "psql --dbname='discourse_development' --single-transaction --variable=ON_ERROR_STOP=1 --username=michael"

Вот! Всё, что я зачеркнул, верно. Ошибка только в порте.

[1] pry(main)> BackupRestore.database_configuration
=> #<struct BackupRestore::DatabaseConfiguration
 host="[REDACTED]",
 port=5432,
 username="[REDACTED]",
 password="[REDACTED]",
 database="[REDACTED]">
[2] pry(main)> BackupRestore::DatabaseRestorer.psql_command
=> "PGPASSWORD='[REDACTED]' psql --dbname='[REDACTED]' --single-transaction --variable=ON_ERROR_STOP=1 --host=[REDACTED] --port=5432 --username=[REDACTED]"

Также ещё раз подчеркну: пустой экземпляр может подключиться к базе данных для всех операций, кроме восстановления из резервной копии.

Что такое

ActiveRecord::Base.connection_pool.db_config.configuration_hash
[3] pry(main)> ActiveRecord::Base.connection_pool.db_config.configuration_hash
=> {:adapter=>"postgresql",
 :pool=>8,
 :connect_timeout=>5,
 :socket=>"/var/run/postgresql",
 :host=>"[REDACTED]",
 :port=>9432,
 :backup_port=>5432,
 :username=>"[REDACTED]",
 :password=>"[REDACTED]",
 :host_names=>["[REDACTED]"],
 :database=>"[REDACTED]",
 :prepared_statements=>false,
 :idle_timeout=>30,
 :reaping_frequency=>30,
 :advisory_locks=>true}

Ах! Вам также нужно установить

DISCOURSE_DB_BACKUP_PORT: 9432

и тогда всё должно заработать.

РЕДАКТИРОВАНИЕ: эта настройка по умолчанию действовала уже некоторое время, но, похоже, причинила больше проблем, чем пользы.

FIX: clear db_backup_port default value by Supermathie · Pull Request #25316 · discourse/discourse · GitHub также должно решить эту проблему и избежать подобных путаниц для будущих путешественников

Большое спасибо! Спасибо!