A restauração falha devido à reconexão do banco de dados não funcionar

Situação:

Uma instalação do Discourse com dois contêineres, com web e dados em hosts diferentes.

Problema

Uma restauração via linha de comando de um arquivo grande, de 22 GB, a partir de uma versão muito antiga do Discourse (ou seja, muitas migrações demoradas para executar) falha após 45 minutos, logo após a restauração do banco de dados.

Reconnecting to the database...
EXCEPTION: PQconsumeInput() could not receive data from server: Connection timed out
SSL SYSCALL error: Connection timed out
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in 'PG::Connection#exec'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in 'PG::Connection#async_exec'

…

from /var/www/discourse/app/models/backup_metadata.rb:16:in 'BackupMetadata.update_last_restore_date'
from /var/www/discourse/lib/backup_restore/database_restorer.rb:31:in 'BackupRestore::DatabaseRestorer#restore'
from /var/www/discourse/lib/backup_restore/restorer.rb:61:in 'BackupRestore::Restorer#run'
from script/discourse:242:in 'DiscourseCLI#restore'

…

Trying to rollback...
Cleaning stuff up...
Dropping functions from the discourse_functions schema...
Something went wrong while dropping functions from the discourse_functions schema
PQsocket() can't get socket descriptor

Teoria

O Discourse usa uma segunda conexão de banco de dados para a restauração em si e outra para a migração.
Quando essas etapas terminam, ele se reconecta ao banco de dados na conexão primária e executa BackupMetadata.update_last_restore_date, que falha imediatamente.

A razão para essa falha parece ser que a reconexão ao banco de dados não reconecta de fato.
Ela reutiliza o ConnectionHandler em cache. Veja aqui. E essa conexão é perdida após 45 minutos.

handler = connection_handlers[handler_key(spec)]

unless handler
  handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
  handler.establish_connection(spec.config)
  connection_handlers[handler_key(spec)] = handler
end

ActiveRecord::Base.connection_handler = handler

Solução temporária

O Postgres tem tcp_keepalives_idle = 0, o que significa que ele usa a configuração do sistema operacional como padrão.
O SO tem net.ipv4.tcp_keepalive_time = 7200 (2 horas)

ALTER SYSTEM SET tcp_keepalives_idle = 60; 
ALTER SYSTEM SET tcp_keepalives_interval = 30; 
ALTER SYSTEM SET tcp_keepalives_count = 5;

Isso impede que a conexão seja fechada e resolve o problema.

Correção sugerida

Fazer com que o código de reconexão execute

ActiveRecord::Base.connection_handler.clear_all_connections! ou algo similar antes de reestabelecer a conexão.

Ou, de forma mais genérica, adicionar um parâmetro reconnect ao establish_connection que ignore o handler em cache.