You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Only successful jobs seem to decrease job_batch.pending_jobs, leading to batches that remain "unfinished" #61835
I am submitting a batch of jobs using Bus::batch($jobs)->allowFailures()->finally(...)->dispatch(), onto a queue with a worker running
I have a job with use Batchable, Queueable, SerializesModels, InteractsWithQueue; and the attribute #[Tries(1)] (and the associated import) (I have also tried setting public int $tries = 1;)
When all of the jobs are successful (i.e. throw no errors), then I see pending_jobs steadily decrease in the job_batches table, and once all jobs are processed, my finally method is called, and I eventually see the job_batches entry updated with a value for finished_at
If I make all of the jobs fail (i.e. throw an exception), then I see failed_jobs and failed_job_ids increase, but pending_jobs remains unchanged throughout. Once all jobs have been processed, my finally method is called, but a value for finished_at is never set on the job_batch and pending_jobs still equals total_jobs. I also see entries in the failed_jobs table for each job
If I have a mixture of successful and failing jobs, then only the successful ones decrease pending_jobs. Once all jobs have been processed, my finally method is called, but a value for finished_at is never set on the job_batch
Steps To Reproduce
Job class defined to only be tried once, and that throws an exception (RuntimeException in my case) in the handle() method
Submit a batch of these jobs using Bus::batch($jobs)->allowFailures()->finally(...)->dispatch()
I saw your PR and I just wanted to ask a question about the pending_jobs counter: Does it make sense for this to remain the same if failed_jobs has increased?
Apologies, as I'm new to things in Laravel, but I was kind of expecting behaviour along the lines:
When a job succeeds:
pending_jobs decreases by 1
failed_jobs remains unchanged
When a job fails temporarily (and has retries left):
pending_jobs does not change
failed_jobs does not change
When a job fails permanently (all allowed tries exhausted):
pending_jobs decreases by 1
failed_jobs increases by 1
When you retry a batch, for every failed job re-queued:
pending_jobs increases by 1
and failed_jobs decreases by 1
Otherwise it seems like we're double counting things?
(Please feel free to point me elsewhere if this should be a Q & A question or something else)
Hi @stephendnicholas, I don't think it's double counting. The counters are designed around retries:
pending_jobs counts jobs that haven't succeeded yet. A failed job stays in it on purpose, so it can still be retried with php artisan queue:retry-batch {id}. When a retried job succeeds, pending_jobs goes down and its ID is removed from failed_job_ids.
failed_jobs counts recorded failures. It's incremented when a job fails and isn't decremented on retry; only failed_job_ids is updated.
The batch then uses two different completion checks:
pending_jobs === failed_jobs means every job has run once, so finally() fires (UpdatedBatchJobCounts::allJobsHaveRanExactlyOnce()).
pending_jobs === 0 means every job succeeded, so finished_at is set and then() fires.
That's why your all-failing batch runs finally() but never gets finished_at. #61850 proposed changing that and was closed, so it's the current behaviour. In the meantime:
Use finally() to run your "done" logic, or check $batch->pendingJobs === $batch->failedJobs and $batch->hasFailures().
Use php artisan queue:prune-batches --unfinished=72 so these batches still get pruned.
Activity
stephendnicholas commentedon Oct 5, 2026
Hi @shuvroroy,
Thanks for looking at this so quickly
I saw your PR and I just wanted to ask a question about the pending_jobs counter: Does it make sense for this to remain the same if failed_jobs has increased?
Apologies, as I'm new to things in Laravel, but I was kind of expecting behaviour along the lines:
Otherwise it seems like we're double counting things?
(Please feel free to point me elsewhere if this should be a Q & A question or something else)
dwivedianuj9118 commentedon Oct 26, 2026
Hi @stephendnicholas, I don't think it's double counting. The counters are designed around retries:
pending_jobscounts jobs that haven't succeeded yet. A failed job stays in it on purpose, so it can still be retried withphp artisan queue:retry-batch {id}. When a retried job succeeds,pending_jobsgoes down and its ID is removed fromfailed_job_ids.failed_jobscounts recorded failures. It's incremented when a job fails and isn't decremented on retry; onlyfailed_job_idsis updated.The batch then uses two different completion checks:
pending_jobs === failed_jobsmeans every job has run once, sofinally()fires (UpdatedBatchJobCounts::allJobsHaveRanExactlyOnce()).pending_jobs === 0means every job succeeded, sofinished_atis set andthen()fires.That's why your all-failing batch runs
finally()but never getsfinished_at. #61850 proposed changing that and was closed, so it's the current behaviour. In the meantime:finally()to run your "done" logic, or check$batch->pendingJobs === $batch->failedJobsand$batch->hasFailures().php artisan queue:prune-batches --unfinished=72so these batches still get pruned.[13.x] Decrement pending jobs when a batch job fails