Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

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

Open
justlunix opened this issue Mar 19, 2025 · 1 comment
Open

Comments

@justlunix
Copy link

justlunix commented Mar 19, 2025

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
Copy link

Thank you for reporting this issue!

As Laravel is an open source project, we rely on the community to help us diagnose and fix issues as it is not possible to research and fix every issue reported to us via GitHub.

If possible, please make a pull request fixing the issue you have described, along with corresponding tests. All pull requests are promptly reviewed by the Laravel team.

Thank you!

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

2 participants