Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

FrankClark's avatar

Laravel Batch Jobs - Call Finally even if error

Hello there,

I am using batches to run a series of jobs. I thought logically, if you use allowFailures() that the finally() callback would still get called

$myThingsBatches = $myThings->map(static function ($item) {
            return [
                new createPartOne($item->id),
                new createPartTwo($item->id),
            ];
        });
        Bus::batch($myThingsBatches)->then(function (Batch $batch) use ($parentThing) {
            Log::info("Inside 'then'");
        })->catch(function (Batch $batch, Throwable $exception) {
            Log::info("Inside catch : " . $exception->getMessage());
        })->finally(function (Batch $batch) use ($parentThing) {
            Log::info("Inside finally");
            CreateMainThing::dispatch($parentThing->id);
        })->allowFailures()->dispatch();

So, if one of the batches in $myThingsBatches times out, the finally callback never happens. My desired outcome is that the finally callback gets run no matter what.

As documented the catch-> only gets called for the first failure in the batch, so that isn't suitable either as i want to wait for all of the jobs to have either finished or failed before what happens in finally is executed.

Any ideas ?

0 likes
8 replies
avivais's avatar

@frankclark were you able to overcome this? For me, it seems as the finally block sometimes gets called with failures, sometimes not, still trying to figure it out

Snapey's avatar

@avivais finally seems to qualify that every job in the batch must have run (successfully) at least once

avivais's avatar

@Snapey it seems sporadic... Batch can run several iterations with all jobs failing (with allowFailures) - Sometimes finally is called, sometimes it's not... Can't understand why

FrankClark's avatar

@avivais no, i just added each 'thing' in the process to a database table with a status column. I then just attempt various retries dependent on how things went. What i had in the 'finally' then only runs when everything is has either retried or failed completely. Hard to explain as i dumbed down my question rather than having the actual use case but ultimately finally just doesn't work how i'd like it to. I assume however that it is this way for a good reason.

I can't say i experienced what you are describing tough. The finally seemed to never get called if one of the jobs failed.

In my case it was nearly always a timeout, so i created a new 'long_running' queue type that had extra timeouts and retry intervals.

1 like
avivais's avatar

@FrankClark I investigated a bit more, and found the root cause of missing finally call - There are cases where X jobs are batched, but only part of them report failure/success - Seems as some are just "lost" from the batch (While appearing in failed_jobs DB table) - In all such cases where there's a gap, finally won't get called. Still trying to figure out how to workaround this.

1 like
erycson's avatar

try this:

<?php

	public function handle()
    {
		try {
			... Your code here, which throws an error
		} catch (catch (Exception $e) {
			$this->fail($e);
		}
	}

after I did it like this, finally() started working again

Please or to participate in this conversation.