在ApplicationJob集成Sidekiq::Job后,如何让around_perform回调生效?
解决Sidekiq Job中around_perform回调未触发的问题
问题根源
你的代码核心问题在于子类重写了perform方法,完全跳过了父类ApplicationJob中包含回调逻辑的perform实现。父类里的perform方法负责触发run_callbacks(:perform),但子类直接覆盖该方法后,回调流程根本没机会执行,导致set_paper_trail_whodunnit永远不会被调用。
解决方案
方案1:遵循父类设计,子类实现perform!而非perform
父类ApplicationJob原本就设计了perform!作为子类需要实现的业务逻辑入口,perform方法专门负责回调的触发。修改子类代码,把业务逻辑移到perform!中:
class ExampleJob < ApplicationJob def perform!(record_id) Record.find(record_id).update!(column: new_value) end end
这样当Sidekiq调用perform时,会执行父类的perform方法,触发around_perform回调,再调用子类的perform!执行业务逻辑,PaperTrail的whodunnit就能正确设置。
方案2:调整父类逻辑,强制回调触发(不推荐,破坏设计约定)
如果不想修改子类代码,可以在父类中用prepend来确保回调逻辑被执行,但这种方式会增加复杂度,不如方案1简洁:
class ApplicationJob include Sidekiq::Job extend ActiveModel::Callbacks sidekiq_options queue: :default define_model_callbacks :perform around_perform :set_paper_trail_whodunnit def set_paper_trail_whodunnit PaperTrail.request.whodunnit = self.class.name yield ensure PaperTrail.request.whodunnit = nil end # 用prepend确保回调逻辑优先执行 module PerformCallbackWrapper def perform(*args) run_callbacks(:perform) do super(*args) end end end prepend PerformCallbackWrapper def perform!(*_args) raise NotImplementedError, 'Missing your #perform! method implementation' end end
这样即使子类重写了perform,prepend的模块会先执行回调逻辑,再调用子类的perform方法。
额外说明
- 如果你想使用Sidekiq原生的回调,可以直接用Sidekiq提供的
around_perform钩子(不需要ActiveModel::Callbacks),写法如下:
class ApplicationJob include Sidekiq::Job sidekiq_options queue: :default sidekiq_options around_perform: :set_paper_trail_whodunnit def set_paper_trail_whodunnit PaperTrail.request.whodunnit = self.class.name yield ensure PaperTrail.request.whodunnit = nil end def perform(*args) perform!(*args) end def perform!(*_args) raise NotImplementedError, 'Missing your #perform! method implementation' end end
这种方式不需要手动处理run_callbacks,Sidekiq会自动触发钩子逻辑,也能避免和ActiveJob的冲突。
内容的提问来源于stack exchange,提问作者Richard Wright
相关产品推荐
相关产品推荐

