Rails 6 迁移在使用多个数据库后出现奇怪的错误

问题描述 投票:0回答:1

我在项目中使用两个数据库,使用默认的 Rails 6 支持。

数据库.yml:-

default: &default
  adapter: postgresql
  migrations_paths: "db/migrate/primary"
  encoding: unicode
  min_messages: warning
  username: ########
  password: ########
  pool: 5
  timeout: 5000
  host_name: localhost

development:
  primary:
    <<: *default
    database: primary_db
  hrm:
    <<: *default
    database: hrm_db
    migrations_paths: "db/migrate/hrm"

二级数据库的模型如下:

class HRM::ServiceHistory < ApplicationRecord
  connects_to database: { writing: :hrm, reading: :hrm }

  belongs_to :employee
  belongs_to :designation
.
.

迁移文件:-

class ModifyDesigs < ActiveRecord::Migration[6.0]
  def change
    add_column :service_histories, :basic_scale, :integer
    remove_column :employees, :designation_id

    add_column :employees, :current_position_id, :integer

    HRM::ServiceHistory.reset_column_information
    HRM::Employee.reset_column_information
    puts "\n\n=================== #{HRM::Employee.first.name} \n\n"

    HRM::Employee.all.each do |emp|
        emp.service_histories.each do |sh|
            des = sh.designation
            sh.basic_scale = des.basic_scale
            sh.save!
        end
        sh = emp.service_histories.order('appointment_date desc').limit(1).first
        if sh
            emp.current_position = sh
            emp.save!
        end
    end
  end
end

所有正常的 DDL 语句都在运行文件,即使

HRM::Employee.first.name
不会引发错误,但进一步的语句会引发错误:

== 20200409162158 ModifyDesigs: migrating =====================================
-- add_column(:service_histories, :basic_scale, :integer)    -> 0.0041s
-- add_column(:service_histories, :scale, :integer)    -> 0.0005s
-- add_column(:service_histories, :scale_type, :string, {:limit=>1})    -> 0.0005s
-- remove_column(:employees, :designation_id)    -> 0.0050s
-- add_column(:employees, :current_position_id, :integer)    -> 0.0004s
-- add_index(:employees, :current_position_id)    -> 0.0114s
-- add_foreign_key(:employees, :service_histories, {:column=>:current_position_id})    -> 0.0044s


=================== Employee Name

rails aborted!
ActiveRecord::StatementInvalid: PG::ConnectionBad: connection is closed
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:65:in `exec'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:65:in `block (2 levels) in query'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:64:in `block in query'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:718:in `block (2 levels) in log'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:717:in `block in log'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:708:in `log'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:63:in `query'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:98:in `query_value'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:383:in `release_advisory_lock'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/migration.rb:1384:in `ensure in with_advisory_lock'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/migration.rb:1385:in `with_advisory_lock'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/migration.rb:1229:in `migrate'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/migration.rb:1061:in `up'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/migration.rb:1036:in `migrate'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/tasks/database_tasks.rb:238:in `migrate'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/railties/databases.rake:114:in `block (4 levels) in <top (required)>'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/railties-6.0.2.1/lib/rails/commands/rake/rake_command.rb:23:in `block in perform'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/railties-6.0.2.1/lib/rails/commands/rake/rake_command.rb:20:in `perform'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/railties-6.0.2.1/lib/rails/command.rb:48:in `invoke'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/railties-6.0.2.1/lib/rails/commands.rb:18:in `<top (required)>'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in `block in require'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:291:in `load_dependency'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in `require'...


Caused by:
PG::ConnectionBad: connection is closed
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:65:in `exec'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:65:in `block (2 levels) in query'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'...
.
.
Caused by:
StandardError: An error has occurred, this and all later migrations canceled:

PG::ConnectionBad: connection is closed
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:92:in `exec'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:92:in `block (2 levels) in execute'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'...
.
.
Caused by:
ActiveRecord::StatementInvalid: PG::ConnectionBad: connection is closed
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:92:in `exec'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:92:in `block (2 levels) in execute'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'...
.
.
Caused by:
PG::ConnectionBad: connection is closed
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:92:in `exec'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:92:in `block (2 levels) in execute'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'...
.
.
Caused by:
NoMethodError: undefined method `basic_scale=' for #<HRM::ServiceHistory:0x000000000f3b7c98>
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activemodel-6.0.2.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
/var/www/dris/releases/315/db/migrate/hrm/20200409162158_modify_desigs.rb:20:in `block (3 levels) in change'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/relation/delegation.rb:85:in `each'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/relation/delegation.rb:85:in `each'
/var/www/dris/releases/315/db/migrate/hrm/20200409162158_modify_desigs.rb:18:in `block (2 levels) in change'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/relation/delegation.rb:85:in `each'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/relation/delegation.rb:85:in `each'
/var/www/dris/releases/315/db/migrate/hrm/20200409162158_modify_desigs.rb:17:in `block in change'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_handling.rb:269:in `swap_connection_handler'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_handling.rb:176:in `with_handler'
/home/deployer/.rvm/gems/ruby-2.5.1/gems/activerecord-6.0.2.1/lib/active_record/connection_handling.rb:132:in `connected_to'
/var/www/dris/releases/315/db/migrate/hrm/20200409162158_modify_desigs.rb:15:in `change'..
.
.

这是单次运行的错误。我尝试了很多次,有时任务挂在

puts HRM::Employee.first.name
上,有时会出现如上所示的错误。看起来并发迁移正在运行,但它们不应该运行。虽然错误日志的最后一段描述了我迭代中的一些错误,但是
basic_scale=
已定义并且我已经在控制台中进行了测试。即使此迁移也可以从 Rails 控制台成功运行。 在使用两个数据库和迁移到Rails 6之前,我从未遇到过这样的问题。

编辑:我尝试在 DML 语句点拆分迁移,并且迁移成功运行。如果我在一次迁移中重置列信息,则不应导致此问题。很奇怪为什么拆分迁移可以解决问题。

ruby-on-rails postgresql rails-migrations ruby-on-rails-6 multiple-databases
1个回答
0
投票

这似乎是在迁移

together
中调用模型自己的连接(例如调用
model.save
Model.connection.execute)并调用任何
ActiveRecord::Migration
方法(如
create_table
等)时发生的。它破坏了 Rails 的内部连接处理,导致奇怪的行为。我个人遇到过
connection closed
错误,而且它也写入了错误的
schema_information
表。

这似乎是 Rails 团队需要修复的一个错误。在那之前:将迁移分成两部分将解决这个问题:一个用于修改数据库,另一个用于调用模型(

.save
等)(就像提到的那样)

示例:

# First modify table
class ModifyTables < ActiveRecord::Migration[7.0]
  def change
    add_column :foo, :bar, :string
    drop_column :foo, :baz
  end
end

# THEN modify data
class ModifyData < ActiveRecord::Migration[7.0]
  def up
    Foo.find_each do |foo|
      foo.update!(bar: "baz")
    end
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.