Skip to content

ShouldDispatchAfterCommit does not work after child transactions are committed #49057

@hansnn

Description

@hansnn

Laravel Version

10.32.1

PHP Version

8.2

Description

When a child transaction is committed inside of a parent transaction, any events with the ShouldDispatchAfterCommit interface that are dispatched after the child transaction has committed, but before the parent transaction is committed, will be dispatched immediately.

The problem is related to that the dispatcher adds the event listeners using DatabaseTransactionManager@addCallback, and that this method only adds the callback if it has any pendingTransactions - which are flushed whenever a transaction is committed.

Steps To Reproduce

I wrote a failing test case in ShouldDispatchAfterCommitEventTest.php that illustrates the problem:

public function testItOnlyDispatchesEventsAfterTheRootTransactionIsCommitted()
{
    Event::listen(ShouldDispatchAfterCommitTestEvent::class, ShouldDispatchAfterCommitListener::class);

    DB::transaction(function () {
        // Begin and commit a child transaction. This line causes the test to fail.
        DB::transaction(function () {});

        Event::dispatch(new ShouldDispatchAfterCommitTestEvent);

        $this->assertFalse(ShouldDispatchAfterCommitTestEvent::$ran);
    });

    $this->assertTrue(ShouldDispatchAfterCommitTestEvent::$ran);
}

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