確認環境
$ bundle exec ruby --version
ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-darwin19]
$ bundle exec rails --version
Rails 6.0.4.6
前提
このようなモデル/データがあるとします。
$ rails c
Loading development environment (Rails 6.0.4.6)
irb(main):001:0> u = SampleUser.last
(0.8ms) SELECT sqlite_version(*)
SampleUser Load (0.1ms) SELECT "sample_users".* FROM "sample_users" ORDER BY "sample_users"."id" DESC LIMIT ? [["LIMIT", 1]]
=> #<SampleUser id: 1, name: "hoge", created_at: "2022-08-24 15:34:58", updated_at: "2022-08-24 15:34:58">
Timeout の中でトランザクション
irb(main):002:1* Timeout.timeout(2) do
irb(main):003:2* ActiveRecord::Base.transaction do
irb(main):004:2* u = SampleUser.find(1)
irb(main):005:2* u.name = 'new name'
irb(main):006:2* u.save
irb(main):007:2*
irb(main):008:2* sleep(5)
irb(main):009:1* end
irb(main):010:0> end
(0.1ms) begin transaction
SampleUser Load (0.2ms) SELECT "sample_users".* FROM "sample_users" WHERE "sample_users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SampleUser Update (1.4ms) UPDATE "sample_users" SET "name" = ?, "updated_at" = ? WHERE "sample_users"."id" = ? [["name", "new name"], ["updated_at", "2022-08-27 06:18:46.114153"], ["id", 1]]
(2.3ms) commit transaction
Traceback (most recent call last):
4: from (irb):2
3: from (irb):3:in `block in irb_binding'
2: from (irb):8:in `block (2 levels) in irb_binding'
1: from (irb):8:in `sleep'
Timeout::Error (execution expired)
トランザクションが commit されており、rollback されていません。
トランザクションの中でTimeout
irb(main):013:1* ActiveRecord::Base.transaction do
irb(main):014:2* Timeout.timeout(2) do
irb(main):015:2* u = SampleUser.find(1)
irb(main):016:2* u.name = 'new name 222'
irb(main):017:2* u.save
irb(main):018:2*
irb(main):019:2* sleep(5)
irb(main):020:1* end
irb(main):021:0> end
(0.1ms) begin transaction
SampleUser Load (0.1ms) SELECT "sample_users".* FROM "sample_users" WHERE "sample_users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SampleUser Update (0.3ms) UPDATE "sample_users" SET "name" = ?, "updated_at" = ? WHERE "sample_users"."id" = ? [["name", "new name 222"], ["updated_at", "2022-08-27 06:20:45.414843"], ["id", 1]]
(0.4ms) rollback transaction
Traceback (most recent call last):
4: from (irb):12
3: from (irb):13:in `block in irb_binding'
2: from (irb):18:in `block (2 levels) in irb_binding'
1: from (irb):18:in `sleep'
Timeout::Error (execution expired)
この場合は、rollbackされています。
Timeout の中でトランザクション (Timeoutの第2引数に例外指定)
Timeout.timeoutのTimeoutの第2引数に例外を指定すると、rollbackされます。
内部の動きについては、こちらの記事に書いてあるようです。(私は、まだ理解していません)
irb(main):025:0>
irb(main):026:1* Timeout.timeout(2, Timeout::Error) do
irb(main):027:2* ActiveRecord::Base.transaction do
irb(main):028:2* u = SampleUser.find(1)
irb(main):029:2* u.name = 'new name 333'
irb(main):030:2* u.save
irb(main):031:2*
irb(main):032:2* sleep(5)
irb(main):033:1* end
irb(main):034:0> end
(0.1ms) begin transaction
SampleUser Load (0.1ms) SELECT "sample_users".* FROM "sample_users" WHERE "sample_users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SampleUser Update (0.5ms) UPDATE "sample_users" SET "name" = ?, "updated_at" = ? WHERE "sample_users"."id" = ? [["name", "new name 333"], ["updated_at", "2022-08-27 06:22:58.254487"], ["id", 1]]
(0.5ms) rollback transaction