Envek / after_commit_everywhere

Use ActiveRecord transactional callbacks outside of models, literally everywhere in your application.
MIT License
678 stars 22 forks source link

Unexpected behaviour in ActiveJob callbacks #32

Open shahidkhaliq opened 1 month ago

shahidkhaliq commented 1 month ago

Hello, thanks for all the hard work on this gem! I've been trying to use this gem to prevent ActiveJob jobs from enqueueing within transactions but have run into some unexpected behavior. If my job looks like the following:

class TestJob < ActiveJob::Base
  before_enqueue do |job|
    puts "1"
  end

  around_enqueue do |job, block|
    puts "2"
    block.call
  end

  include AfterCommitEverywhere

  around_enqueue do |job, block|
    puts "3"
    after_commit { block.call }
  end

  around_enqueue do |job, block|
    puts "4"
    block.call
  end

  def perform; end
end

And I try to enqueue it from within a transaction:

ActiveRecord::Base.transaction do
  TestJob.perform_later
end

It outputs 123 1234 instead of 1234 that I'm expecting. It seems like all the callbacks preceding the callback that has after_commit are run twice instead of once.

This is on Rails 6.0.6.1 with after_commit_everywhere (1.1.0).

Am I doing something wrong here or is this a bug in the gem?

Envek commented 1 month ago

To be honest I'm not sure why this code runs like that.

However, it doesn't seem that your intention to postpone enqueue from callbacks would work at all, as ActiveJob callbacks are built with plain ActiveSupport callbacks and you need to halt callback chain by throwing :abort, see: https://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html#method-i-run_callbacks

Anyway, I would recommend implementing this in some other way, e.g. by redefining the whole enqueue method of ActiveJob job.

Also see https://github.com/Envek/after_commit_everywhere/issues/27#issuecomment-1692865436