Rails 5.1.4 + psql,ActiveRecord 奇怪的双事务开始,当期待一个



我认为机架超时设置的问题实际上是ActiveRecord::Base.transaction的问题

当请求命中我们的某个更新终结点,并且该更新在事务中处理时

即使是像这样简单的事情

def update
ActiveRecord::Base.transaction do
@note.find(params[:id])
@note.update(text: "foo")
end
end

我们的服务器日志如下所示:

started /foo
BEGIN
BEGIN
UPDATE
COMMIT

人们会期望:

started /foo
BEGIN
UPDATE
COMMIT

问题是当发生错误时,所有事务都不会回滚。我们的日志如下所示:

started /foo
BEGIN
BEGIN
UPDATE
COMMIT
ROLLBACK

而不是:

started /foo
BEGIN
UPDATE
ROLLBACK

奇怪的部分

在开发模式下,当我们以任何方式编辑任何 rails 文件时。该操作按预期工作,只需一个 BEGIN。重新启动服务器时,有两个 BEGIN。此外,这仅在控制器中发生,而不是在控制台中,甚至不在控制台中调用控制器时。可以做到:

rails c
# app#action "path"
app.put "/foo"
  • 此问题存在于服务器(rails s(的重新启动中,但是如果我编辑代码的任何部分并且rail重新加载代码库,则操作将按预期运行。
  • 此外,这只会发生在控制器中,使用相同的代码块并将其粘贴到重新设置的作业中,它按预期工作。
  • 从控制台 app.put "/note" 调用终结点按预期工作。
  • 调用 note.update 按预期工作
  • Rspec 控制器和集成测试按预期工作。
  • Note.transaction 按预期工作,尽管日志中仍然存在双 BEGIN
  • Note.last.update 按预期工作,尽管日志中仍然存在双 BEGIN

  • ActiveRecord::Base.transaction 无法按预期工作。

导轨 5.1.4

以前有人见过这样的问题吗?可能是 AR 设置还是从宝石中引入?

在具有两个开始块的请求中,第一个开始是我们在控制器中打开的事务。那么第二次预更新从哪里开始?

更新

我在这里打开了一个关于活动记录的问题。我将在这里总结一下。

我认为这可能是(尽管松散地是 AR 问题(的原因是第二个 BEGIN 实际上来自使用事务的更新方法。

堆栈跟踪来自 lib/active_record/connection_adapters/postgresql/database_statements.rb:ln 130 我在这里添加了一个 put 调用者,这是在调用更新语句之前最后一次调用它,在这种情况下:

2 用于我们的应用程序 1 表示其他 Rails 应用程序。

我们的应用程序

active_record/connection_adapters/abstract/transaction.rb:130:in `initialize'
active_record/connection_adapters/abstract/transaction.rb:156:in `new'
active_record/connection_adapters/abstract/transaction.rb:156:in `block in begin_transaction'
monitor.rb:226:in `mon_synchronize'
active_record/connection_adapters/abstract/transaction.rb:152:in `begin_transaction'
active_record/connection_adapters/abstract/transaction.rb:193:in `block in within_new_transaction'
monitor.rb:226:in `mon_synchronize'
active_record/connection_adapters/abstract/transaction.rb:191:in `within_new_transaction'
active_record/connection_adapters/abstract/database_statements.rb:235:in `transaction'
active_record/transactions.rb:210:in `transaction'
active_record/transactions.rb:381:in `with_transaction_returning_status'
active_record/persistence.rb:283:in `update'
app/controllers/debugging_transactions_controller.rb:18:in `block in update'
active_record/connection_adapters/abstract/database_statements.rb:235:in `block in transaction' <<<<<<<<
active_record/connection_adapters/abstract/transaction.rb:194:in `block in within_new_transaction'
monitor.rb:226:in `mon_synchronize'
active_record/connection_adapters/abstract/transaction.rb:191:in `within_new_transaction'
active_record/connection_adapters/abstract/database_statements.rb:235:in `transaction'
active_record/transactions.rb:210:in `transaction'
app/controllers/debugging_transactions_controller.rb:12:in `update' #ActiveRecord::Base.transaction do

新的 Rails 应用程序,具有重复的 Gemfile 和 Gemfile.lock 文件。

active_record/connection_adapters/abstract/transaction.rb:130:in `initialize'
active_record/connection_adapters/abstract/transaction.rb:156:in `new'
active_record/connection_adapters/abstract/transaction.rb:156:in `block in begin_transaction'
monitor.rb:226:in `mon_synchronize'
active_record/connection_adapters/abstract/transaction.rb:152:in `begin_transaction' <<<<<<<<<
active_record/connection_adapters/abstract/transaction.rb:193:in `block in within_new_transaction'
monitor.rb:226:in `mon_synchronize'
active_record/connection_adapters/abstract/transaction.rb:191:in `within_new_transaction'
active_record/connection_adapters/abstract/database_statements.rb:235:in `transaction'
active_record/transactions.rb:210:in `transaction'
app/controllers/debugging_transactions_controller.rb:11:in `update' # ActiveRecord::Base.transaction do

我们的应用程序正在点击 persistance.rb 的更新操作,该操作确实将操作包装在事务中 但是为什么?

更新我想出了什么,但没有弄清楚为什么。

https://github.com/rails/rails/blob/813af4655f9bf3c712cf50205eebd337070cee52/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb#L151 第一次在普通rails应用程序中调用它 交易@stack.size为0,AR使用可加入的RealTransaction。然后在 https://github.com/rails/rails/blob/813af4655f9bf3c712cf50205eebd337070cee52/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb#L228

RealTransaction是可连接的,因此rails运行收益(您的区块(

在我们的应用程序中,堆栈大小为零,并且它使用的是 NullTransaction。这是不可加入的,然后导致AR将model.update又名with_transaction_returning_status包装在一个全新的事务中。似乎这是线程问题还是连接问题?

所以我想通了。这是一个美洲狮工人配置,我相信这导致了奇怪的线程/双连接问题。

在我们的配置/puma.rb 文件中,我们有

on_worker_boot do
ApplicationRecord.establish_connection if defined?(ActiveRecord)
end

将其更改为此解决了问题。

on_worker_boot do
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end

奇怪的是ApplicationRecord#establish_connection != ActiveRecord::Base#establish_connection

最新更新