我认为与机架超时设置有关的问题实际上与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"
Note.last.update可以按预期工作,尽管日志中仍然存在双BEGIN
ActiveRecord :: Base.transaction无法正常工作。
Rails 5.1.4
有人以前见过这样的问题吗?是可能的AR设置,还是可能是宝石引入的?
在具有两个开始块的请求中,第一个开始是我们正在控制器中打开的事务。那么第二个预更新从哪里开始呢?
更新
我在ActiveRecord here上开了一个问题。我将在这里总结一下。
我认为这可能(尽管从广义上讲是一个AR问题)是第二个BEGIN实际上来自使用事务的update method。
来自的堆栈跟踪 lib / active_record / connection_adapters / postgresql / database_statements.rb:ln 130 在这种情况下,我在最后一次调用update语句之前在这里添加了puts调用程序,
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运行yield(您的代码块)
在我们的应用程序中,堆栈大小为零,并且正在使用NullTransaction。这是不可连接的,这会导致AR将model.update
aka with_transaction_returning_status
包装在一个全新的事务中。似乎这是线程问题或连接问题?
答案 0 :(得分:0)
所以我想通了。我认为这是一种彪马工人的配置,引起了奇怪的线程/双重连接问题。
在我们的config / 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