Skip to content

Catching errors when using Bus::batch inside of Bus::chain on Sync Queue #55077

@justlunix

Description

@justlunix

Laravel Version

11.44.2

PHP Version

8.2.27

Database Driver & Version

No response

Description

When using Bus::chain(...)->catch(...), the catch callback will be transferred to a Bus::batch inside of the chain. This will result in the same callback to be executed twice, once for the batch and then for the chain. I do not understand why this should happen. The chain and the batch both have providable catch callbacks, so why would a batch receive all of the chain callbacks on top?

Just for the sake of hopefully understanding it better:

Bus::chain([
    Bus::batch([
        new MyJob(),
    ])->catch(static fn() => logger()->info('batch callback')),
])->catch(static fn() => logger()->info('chain callback'));

When the Bus::batch is dispatched onto the queue, it will keep its catch callback outputting "batch callback", but it will also receive the catch callback outputting "chain callback". So if MyJob fails, the batch will output both "batch callback" AND "chain callback". Then the error will bubble up, which will cause the chain to run its catch callback, too, which will output "chain callback" again. Therefore: The chain callback has been called twice.

Another thing.

On the sync queue (like in PHPUnit tests), the catch callback of Bus::batch is run in a transaction, which will even reverse any database changes done in the catch callback. That means I have to add checks inside of the catch callback since it's called twice, but I cannot test those check because my phpunit runs through the sync queue, which will revert any database changes in the first callback.

For reference:

  • Batches are run inside of transaction, which will revert the changes on sync queue: vendor/laravel/framework/src/Illuminate/Bus/Batch.php:187
  • Chain catch callbacks are added to batch, which will make the callback execute twice: vendor/laravel/framework/src/Illuminate/Bus/ChainedBatch.php:100

Steps To Reproduce

Bus::chain(
    Bus::batch([....]),
    Bus::batch([....]),
    Bus::batch([....]),
)->catch(static fn() => logger()->info('hi'))->dispatch();
  1. Create a job chain like the above and make sure the job inside the batch fails.
  2. Configure to use the sync queue, i.e. through calling the code within a phpunit test.
  3. Run the code, check the logs.

For reference:

  • Batches are run inside of transaction, which will revert the changes on sync queue: vendor/laravel/framework/src/Illuminate/Bus/Batch.php:187
  • Chain catch callbacks are added to batch, which will make the callback execute twice: vendor/laravel/framework/src/Illuminate/Bus/ChainedBatch.php:100

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions