For example I have a job called TestQueueJob
which is proccessing using database queue driver, inside the job I call another job called TestSyncJob
which is running in sync mode (TestSyncJob::dispatchSync()
). The issue I am facing now is I need TestSyncJob
to not overlap ever and when I have 2 or more TestQueueJob
jobs running at the same time the issues come. I have tried to implement the job middleware using WithoutOverlapping
class but in sync mode it just skippes the TestSyncJob
job and I need it to wait until the other TestSyncJob
execution is finished and to continue.
TestQueueJob::dispatch(); //running using database queue driver, there are > 1 numprocs in supervisor for the queue
class TestQueueJob implements ShouldQueue
{
public function handle(): void
{
//some code
TestSyncJob::dispatchSync(); //should wait until other TestSyncJob is finished and then run
//some code
}
}
use Illuminate\Queue\Middleware\WithoutOverlapping;
class TestSyncJob implements ShouldQueue
{
public function handle(): void
{
\Log::info('Sync job started!');
sleep(10);
\Log::info('Sync job finished!');
}
public function middleware()
{
return [new WithoutOverlapping(1)];
}
}
I have ended up extending the existing WithoutOverlapping
middleware. It's now waiting for other jobs to finish and proceeds the executing of a job instead of skipping it in a "sync" queue mode.
class CustomWithoutOverlapping extends WithoutOverlapping
{
public function handle($job, $next)
{
$lock = Container::getInstance()->make(Cache::class)->lock(
$this->getLockKey($job), $this->expiresAfter
);
if ($lock->get()) {
try {
$next($job);
} finally {
$lock->release();
}
//START of new code
} elseif ($job->connection === 'sync') {
do {
sleep(1);
} while (!$lock->get());
try {
$next($job);
} finally {
$lock->release();
}
//END of new code
} elseif (!is_null($this->releaseAfter)) {
$job->release($this->releaseAfter);
}
}
}