【发布时间】:2018-08-20 20:21:59
【问题描述】:
我认为机架超时设置的问题实际上是 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) 时,但如果我编辑代码的任何部分并且 rails 重新加载代码库,操作将按预期运行。
- 此外,这仅发生在控制器中,采用相同的代码块并将其粘贴到 resque 作业中,它可以按预期工作。
- 从控制台 app.put "/note" 调用端点按预期工作。
- 调用 note.update 按预期工作
- Rspec 控制器和集成测试按预期工作。
- Note.transaction 按预期工作,但双 BEGIN 仍然存在于日志中
Note.last.update 按预期工作,但日志中仍然存在双 BEGIN
ActiveRecord::Base.transaction 未按预期工作。
Rails 5.1.4
以前有人见过这样的问题吗?可能是 AR 设置还是从 gem 引入的?
在具有两个开始块的请求中,第一个开始是我们在控制器中打开的事务。那么第二次预更新从哪里开始呢?
更新
我在 ActiveRecord here 上打开了一个问题。我会在这里总结一下。
我认为这可能是一个 AR 问题的原因,虽然松散地说是一个 AR 问题,但事实上第二个 BEGIN 实际上来自使用事务的update method。
堆栈跟踪来自 lib/active_record/connection_adapters/postgresql/database_statements.rb:ln 130 我在这里添加了一个 puts 调用者,这是在调用 update 语句之前最后一次调用它,在这种情况下:
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 又名 with_transaction_returning_status 包装在一个全新的事务中。似乎这是一个线程问题或连接问题?
【问题讨论】:
标签: ruby-on-rails activerecord psql puma