- Transactionの中で エラーが発生した場合、後続の処理を続けずに ROLLBACK させ、なおかつエラーをハンドリングして特定の処理をおこないたい
- Transaction で begin rescue end で囲ってしまうと、特定のエラーを rescue するときに、ROLLBACK を発生させるための例外も起こらなくなってしまい、やりたいことが出来ない
- Transaction を内側に、begin rescue end を外側に書いてみる。こうすることで ROLLBACK が起こった後に 例外をキャッチして、特定のエラーハンドリング処理をおこなうということを実現する
class User < ApplicationRecord
validates_uniqueness_of :unique_id
end
def call_inner_transaction(id: , something_wrong: false)
begin
ActiveRecord::Base.transaction do
StripeWebhookSucceededEvent.create!(unique_id: id)
raise 'SOMETHING WRONG' if something_wrong
puts '-' * 100
puts 'EXECUTED!'
puts '-' * 100
end
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
puts '*' * 100
puts "RAISED!"
puts '*' * 100
puts e.message
end
end
dupulicated_id = rand(999_999_999_999)
# EXECUTE
# COMMIT
SomeClass.new.call_inner_transaction(id: dupulicated_id.to_s)
# [88] pry(main)> SomeClass.new.call_inner_transaction(id: dupulicated_id.to_s)
# (0.4ms) BEGIN
# StripeWebhookSucceededEvent Create (0.7ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('225043383392', '2020-01-09 10:53:13')
# ----------------------------------------------------------------------------------------------------
# EXECUTED!
# ----------------------------------------------------------------------------------------------------
# (2.5ms) COMMIT
# => nil
# DUPULICATE and RAISE
# NO EXECUTE
# ROLLBACK
SomeClass.new.call_inner_transaction(id: dupulicated_id.to_s)
# [89] pry(main)> SomeClass.new.call_inner_transaction(id: dupulicated_id.to_s)
# (0.4ms) BEGIN
# StripeWebhookSucceededEvent Create (1.1ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('225043383392', '2020-01-09 10:53:17')
# (2.6ms) ROLLBACK
# ****************************************************************************************************
# RAISED!
# ****************************************************************************************************
# Mysql2::Error: Duplicate entry '225043383392' for key 'index_users_on_unique_id': INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('225043383392', '2020-01-09 10:53:17')
# => nil
# DUPULICATE and RAISE before SOMETHING WRONG
# NO EXECUTE
# ROLLBACK
SomeClass.new.call_inner_transaction(id: dupulicated_id.to_s, something_wrong: true)
# [90] pry(main)> SomeClass.new.call_inner_transaction(id: dupulicated_id.to_s, something_wrong: true)
# (0.4ms) BEGIN
# StripeWebhookSucceededEvent Create (2.6ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('225043383392', '2020-01-09 10:53:24')
# (3.3ms) ROLLBACK
# ****************************************************************************************************
# RAISED!
# ****************************************************************************************************
# Mysql2::Error: Duplicate entry '225043383392' for key 'index_users_on_unique_id': INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('225043383392', '2020-01-09 10:53:24')
# => nil
# SOMETHING WRONG
# NO DUPULICATE
# NO EXECUTE
# RAISE AND ROLLBACK
SomeClass.new.call_inner_transaction(id: rand(999_999_999_999).to_s, something_wrong: true)
# [91] pry(main)> SomeClass.new.call_inner_transaction(id: rand(999_999_999_999).to_s, something_wrong: true)
# (0.9ms) BEGIN
# StripeWebhookSucceededEvent Create (1.0ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('357583484588', '2020-01-09 10:53:28')
# (3.0ms) ROLLBACK
# RuntimeError: SOMETHING WRONG
# from (pry):120:in `block in call_inner_transaction'
def call_outer_transaction(id: , something_wrong: false)
ActiveRecord::Base.transaction do
begin
StripeWebhookSucceededEvent.create!(unique_id: id)
raise 'SOMETHING WRONG' if something_wrong
puts '-' * 100
puts 'EXECUTED!'
puts '-' * 100
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
puts '*' * 100
puts "RAISED!"
puts '*' * 100
puts e.message
end
end
end
dupulicated_id = rand(999_999_999_999)
# EXECUTE
# COMMIT
SomeClass.new.call_outer_transaction(id: dupulicated_id.to_s)
# [93] pry(main)> SomeClass.new.call_outer_transaction(id: dupulicated_id.to_s)
# (0.4ms) BEGIN
# StripeWebhookSucceededEvent Create (0.6ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('64910455241', '2020-01-09 10:54:18')
# ----------------------------------------------------------------------------------------------------
# EXECUTED!
# ----------------------------------------------------------------------------------------------------
# (4.7ms) COMMIT
# => nil
# DUPLUCATED AND RAISED
# NO EXECUTE
# BUT COMMIT HAPPENS
SomeClass.new.call_outer_transaction(id: dupulicated_id.to_s)
# [94] pry(main)> SomeClass.new.call_outer_transaction(id: dupulicated_id.to_s)
# (0.5ms) BEGIN
# StripeWebhookSucceededEvent Create (6.4ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('64910455241', '2020-01-09 10:54:26')
# ****************************************************************************************************
# RAISED!
# ****************************************************************************************************
# Mysql2::Error: Duplicate entry '64910455241' for key 'index_users_on_unique_id': INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('64910455241', '2020-01-09 10:54:26')
# (5.4ms) COMMIT
# => nil
# DUPLUCATED AND RAISED
# NO EXECUTE
# BUT COMMIT HAPPENS
SomeClass.new.call_outer_transaction(id: dupulicated_id.to_s, something_wrong: true)
# [95] pry(main)> SomeClass.new.call_outer_transaction(id: dupulicated_id.to_s, something_wrong: true)
# (1.0ms) BEGIN
# StripeWebhookSucceededEvent Create (1.3ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('64910455241', '2020-01-09 10:54:32')
# ****************************************************************************************************
# RAISED!
# ****************************************************************************************************
# Mysql2::Error: Duplicate entry '64910455241' for key 'index_users_on_unique_id': INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('64910455241', '2020-01-09 10:54:32')
# (4.3ms) COMMIT
# => nil
# SOMETHING WRONG
# NO DUPULICATE
# NO EXECUTE
# BUT RAISE AND ROLLBACK
SomeClass.new.call_outer_transaction(id: rand(999_999_999_999).to_s, something_wrong: true)
# [96] pry(main)> SomeClass.new.call_outer_transaction(id: rand(999_999_999_999).to_s, something_wrong: true)
# (0.5ms) BEGIN
# StripeWebhookSucceededEvent Create (0.8ms) INSERT INTO `users` (`unique_id`, `created_at`) VALUES ('710309047775', '2020-01-09 10:54:37')
# (2.4ms) ROLLBACK
# RuntimeError: SOMETHING WRONG
# from (pry):137:in `block in call_outer_transaction'
Original by Github issue
チャットメンバー募集
何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。