'Laravel-Jobs are only dispatched once on
I got a problem with dispatching jobs on Laravel 9.4.1 with PHP 8.1.3. I have written some jobs which have their own queue (import-meta) but run via the database-connection. When I build my app-environment (docker-compose with a db-container and some worker-containers) and I call MyJob::dispatch(some-stuff) it dispatches the jobs nicely... But only ONCE. Every dispatch-call after the initial one (the one after the build) seems to be ignored, since I'm getting a Illuminate\Foundation\Bus\PendingDispatch-Object back, but it has job:null and the job does not get stored inside the jobs-Table. The database-connection itself is fine tho (checked by calling and writing to a Model before). Logs are empty, failed_jobs-table aswell and I am out of ideas of what's going on there. But I am not 100% sure if that is a userland-problem or actually a laravel-bug itself...
Edit: As Luciano pointed out, some code would be helpfull. So here we go: This is one of my Jobs (MyAppJobBase just has a constructor and some initialization-stuff like loading some models and such):
class MyJob extends MyAppJobBase implements ShouldQueue, ShouldBeUnique
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
{
/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 3;
public function __construct(string $somepayload, int $someID)
{
parent::__construct($somepayload, $someID);
$this->onQueue('import-meta');
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try{
// somelogic
$this->delete(); //muss immer am Ende eines Jobs stehen!
} catch (\Exception $exception){
if(env('APP_DEBUG') == true){
dd($exception);
} else {
if($this->attempts() === 3){
$this->fail($exception);
}
}
}
}
/**
* Handle a job failure.
*
* @param \Throwable $exception
* @return void
*/
public function failed(Throwable $exception)
{
//some failure-handling
}
}
And this his how I call my jobs (there are multiple jobtypes, but all follow the same scheme):
call_user_func_array($myJobModel->jobclass.'::dispatch',['somepayload' => '{}', 'someID' => 25]);
Like I said, the first run of this works fine, but the second- and all runs afterwards are not getting saved to the jobs-table.
Solution 1:[1]
Okay - for anyone comming here via Google - I found a reason and an answer to my problem.
I have opened already a bug-report to laravel, but only time will tell if they actually do something about it. I will post the link at the end of this answer.
In a nutshell this problem usually occures on environments where the machine that dispatches jobs is not the one processing them. And the main culprit here is the ShouldBeUnique-Interface. You see - Laravel stores the locks for those jobs inside its' application-cache. It doesn't matter which QUEUE_CONNECTION you have had setup in your config (or env) - it always stores them inside the application cache. Down the road that means if you try to dispatch a job that has the ShouldBeUnique-Interface Laravel checks only it's own cache to see if the job can be dispatched again. So if your connection is actually "database" and the job gets processed by another worker or gets somehow deleted from the jobs-table the framework just doesn't see it. So if you face this problem (and almost loose your sanity over it like me) you basicly have 4 options.
- You clear your app-cache before dispatching, but that just makes the
ShouldBeUniqueobsolete in the first place, cause then your jobs WILL be dispatched multiple times. - You make your app-cache available for the other machine that processes your jobs. Might be hard to implement tho...
- You check if you can run your
ShouldBeUniqueon the same machine which dispatches them. - If neither of the above is an option for you, you have to implement your own logic.
Link to the bug-report: https://github.com/laravel/framework/issues/41464
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Husky110 |
