Why before_process is called twice if I cancel a running job?

I have a hook that implements before_process/1 and use it to log and pub_sub.

I noticed that, if I have a job currently in executing state, if I call Oban.cancel_job for it, before_process/1 will be called again before after_process(:cancel, …) is called.

Why is that?

This creates some issues to my case since I’m using this hook to send pub_sub messages, meaning that I end up sending a “wrong” executing message event (I send it if before_process/1 is called).

Btw, this seems to only happen using before_process/1, using telemetry [:oban, :job, :start] work fine.

This is by design and intentional. The cancel event is handled by a different process from the job. When the hook fires in a new process, there isn’t any stored/prepared job data, so before_process/1 is called again to reconstruct the job state before calling after_process/3 hooks.

This is done to ensure hooks have consistent job state, including any potential pre-processing that was done in before_process/1. The :start telemetry isn’t fired before cancellation, which is why it works the way you expect.

1 Like

Got it, in that case, is there something that I can see in the before_process job struct that would allow me to identify if it was called to be cancel or not so I can differentiate these calls from the rest?

Generally, the before_process hook should be used for idempotent pre-processing rather than side-effects. But, you can detect whether it’s being called to cancel by checking if the process has a label:

if :proc_lib.get_label(self()) == :undefined do
  # This is for a cancellation call and it isn't running in the job process
else
  # This is running in the job process and the label will be the worker name
end