Help us understand the problem. What is going on with this article?

トランザクションをコミットする前に非同期処理を実行しないほうがいいケース

説明用に、主にRailsを使っている場合を例として取りあげます。次のコード

Task.transaction do
  task = Task.create(task_params)
  NotificationJob.perform_later(task)
end

は、ときどき以下のようなエラーを発生させることがあります。

ActiveJob::DeserializationError: Error while trying to deserialize arguments: Couldn't find Task with 'id'=1

DBからデータをオブジェクトとしてデシリアライズしようとして失敗しています。この原因を説明します。

まず、RDBではデフォルトのトランザクション分離レベルがread committedかそれより厳密であることが多いです1。read committedの場合、あるトランザクションでコミットされたデータは別のトランザクションからも読み取ることができます。

また、Task のレコードは Task.transaction のブロックを抜けるまではコミット済みになりません。このとき、トランザクション内でActive Jobの perform_later を実行すると、キューにジョブが入り、ワーカーがキューからジョブを取り出して処理します。

ワーカーがジョブを取り出すタイミングによっては、Task のレコードを保存するトランザクションがコミットされる前に非同期処理が実行されることがありえます。これが起きると、非同期処理はデータを保存しようといているトランザクションとは別のトランザクションとなり、また、分離レベルがread committed以上であることから、まだDBから読み取ることができないデータをしばしばオブジェクトとしてデシリアライズしようとし、結果的にデータが見つからずに失敗となります。

次のような処理の構造にすると、この問題を回避できます。

# トランザクション内ではレコードの保存だけ実行する
task = Task.transaction do
  Task.create(task_params)
end

# 確実にコミット済みのデータを非同期処理の中で読み取る
NotificationJob.perform_later(task)

  1. PostgreSQLではread committed、MySQL (InnoDB) では、もう一段階厳密な分離レベルであるrepeatable readがデフォルト 

pepabo
「いるだけで成長できる環境」を標榜し、エンジニアが楽しく開発できるWebサービス企業を目指しています。
https://pepabo.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした