Today I reviewed code written by a co-worker and I saw the following:
$job = ProductSync::dispatch(); if ($later) { $job->delay(now()->addMinutes(1)); }
That's it. There is no later code that actually commits it into the queue.
I did not understand it: If the job is indeed put into the queue when ::dispatch() is called, then there is a time window in which a queue worker could take the job, even before the delay is added. That would be a race condition, which I couldn't believe would exist in this framework.
That code is correct; that usage is documented.
How does it work?
Tasks that may be put into the queue use the Dispatchable trait. Running dispatch() returns a PendingDispatch object.
This PendingDispatch class is where the magic happens: In its __destruct method the task is put into the queue!
As soon as the PHP garbage collector notices that the $job variable is not used anymore, it will call the destructor that puts the job into the queue. This won't happen as long as the variable is held somewhere, which makes it a perfectly safe way to allow developers to call additional methods on the job later in the code - and you don't need a final commit() that actually puts the job into the queue.
An indeed magical way to use this magic method.