Rerun dereuromark/cakephp-queue failed jobs

I’m trying to comprehend how failed jobs are re-queued.

markJobFailed documentation says: “Mark a job as Failed, incrementing the failed-counter and Requeueing it”

According to what I understand, my Task should fail 5 times until is completed but it isn’t. It just runs once.

What am I doing wrong? thanks in advance.

PD: I also tried using throw new QueueException(‘Exception demo’); copying the ExceptionExampleTask but without success.

    public $retries = 10;

    public function run(array $data, int $jobId): void
    {
        $job = $this->QueuedJobs->get($jobId);

        $this->io->info($job->failed);

        if ($job->failed === 4) {
            $this->QueuedJobs->markJobDone($job);
        }

        $this->QueuedJobs->markJobFailed($job, 'some reason');

        // throw new QueueException('some exception');
    }

Had to look that up myself but it seems re-queued jobs are only being re-fetched from the queue after the specified timeout (either in the job or as a fallback the timeout of the worker config) has passed.

So e.g. by default there is a timeout of 1800 seconds, aka 30min.
If you job was first fetched at 12:00 and failed (due to your Exception) the first time it will be set as “requeued” but only re-fetched at 12:30 when the next queue worker tries to fetch a job.

Its basically this line here in the QueuedJobsModel

$timeoutAt is the “current time” when the worker tried to run a job and $task['timeout'] is the configured timeout as mentioned above.

So (again) this WHERE clause will only fetch your requeued job if your job failled on a worker which was ran timeout seconds in the past

1 Like

So an example task like

<?php

namespace App\Queue\Task;

use Cake\Console\Exception\StopException;
use Cake\I18n\FrozenTime;
use Cake\Log\Log;
use Queue\Queue\AddInterface;
use Queue\Queue\Task;

class TestTask extends Task implements AddInterface
{

    public $timeout = 10;
    public $retries = 5;

	/**
	 * @param array<string, mixed> $data The array passed to QueuedJobsTable::createJob()
	 * @param int $jobId The id of the QueuedJob entity
	 * @return void
	 */
	public function run(array $data, int $jobId): void {
        $job = $this->QueuedJobs->get($jobId);
        $dateTime = new FrozenTime();
        Log::info('Job ' . $job->id . ' ran at ' . $dateTime . ' and has failed ' . $job->failed);
        throw new StopException('Some error');
	}

    public function add(?string $data): void
    {
        $this->QueuedJobs->createJob('Test');
    }
}

which can be added to the queue via bin/cake queue add Test will result in the following Log entries

2023-03-06 19:44:46 info: Job 135557 ran at 06.03.2023 19:44 and has failed 0
2023-03-06 19:44:52 info: Job 135557 ran at 06.03.2023 19:44 and has failed 1
2023-03-06 19:45:04 info: Job 135557 ran at 06.03.2023 19:45 and has failed 2
2023-03-06 19:45:16 info: Job 135557 ran at 06.03.2023 19:45 and has failed 3
2023-03-06 19:45:27 info: Job 135557 ran at 06.03.2023 19:45 and has failed 4
2023-03-06 19:45:39 info: Job 135557 ran at 06.03.2023 19:45 and has failed 5

And the backend queued jobs view looks like this

1 Like

Thanks! that’s really helpful. It is working as expected