Active Job执行报错时是否触发after_perform回调?含rescue_from相关疑问
Great question—this is one of those Active Job behaviors that’s not spelled out clearly in the official docs, so I totally get why you’re digging into it. Let’s break this down with real-world behavior based on testing and common usage:
Main Question: Does after_perform run if perform throws an exception?
Short answer: No, it won’t be called.
Active Job’s callback flow is tied to the successful completion of the perform method. If perform raises an unhandled exception, the execution pipeline stops immediately before reaching the after_perform hook.
Example to confirm:
class FailingJob < ApplicationJob after_perform do |job| Rails.logger.info("after_perform executed!") end def perform raise "Critical error in perform!" end end
When you enqueue and run this job, you’ll see the exception logged, but never the "after_perform executed!" message—since the exception cuts the flow short.
Subquestion 1: Does implementing rescue_from change this behavior?
Short answer: Yes, it will make after_perform run.
The rescue_from method catches exceptions raised in perform, effectively converting a failed job execution into a "successful" one (from Active Job’s perspective). Once the exception is handled, the callback pipeline resumes, and after_perform will trigger as normal.
Example:
class RescuedJob < ApplicationJob rescue_from StandardError do |e| Rails.logger.info("Caught exception: #{e.message}") end after_perform do |job| Rails.logger.info("after_perform executed!") end def perform raise "Critical error in perform!" end end
Running this job will log both the caught exception message and the after_perform message—since rescue_from prevents the exception from terminating the execution flow.
Subquestion 2: What happens if rescue_from itself throws an error?
Short answer: after_perform won’t run, and the new exception will propagate up.
If your rescue_from handler raises another unhandled exception, Active Job treats this as a job failure. The execution pipeline stops immediately (so after_perform never runs), and the new exception will follow your job’s error handling rules—like triggering retries (if configured) or sending the job to a dead-letter queue.
Example:
class RescueFailingJob < ApplicationJob rescue_from StandardError do |e| Rails.logger.info("Caught initial exception: #{e.message}") raise "Oops, the rescue handler broke too!" # New unhandled exception end after_perform do |job| Rails.logger.info("after_perform executed!") end def perform raise "Critical error in perform!" end end
Running this job will log the initial exception message, but not the after_perform message. The job will be marked as failed, and the second exception will be the one reported in your error tracking (or trigger retries if you’ve set them up).
内容的提问来源于stack exchange,提问作者Matthew Rathbone

