Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[DoctrineBridge] Skip the transaction middleware if the message was not yet received #59971

Copy link
Copy link
Open
@Brewal

Description

@Brewal
Issue body actions

Symfony version(s) affected

6.4

Description

When using the doctrine transaction middleware, for each event dispatched, a transaction is started even if the message is not about to be handled yet. This results in useless "empty" transactions while the message is being sent.

This can lead to poor performance when dispatching many events synchronously

How to reproduce

You can dispatch many multiple events on a bus where the doctrine_transaction is registered, go to the profiler and check the performance tab and the doctrine tab. Here I dispatched 96 events :

Image

Image

Possible Solution

By verifying that the ReceivedStamp exists on the envelope before actually running the middleware, we get rid of those requests and things seems to work properly (I do not see a case where it would not but I might be wrong). In my case, it resulted in huge performance boost on production :

class DoctrineTransactionMiddleware extends AbstractDoctrineMiddleware
{
    protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope
    {
        if (!$envelope->last(ReceivedStamp::class) instanceof StampInterface) {
            return $stack->next()->handle($envelope, $stack);
        }

        $entityManager->getConnection()->beginTransaction();

        $success = false;
        try {
            $envelope = $stack->next()->handle($envelope, $stack);
            $entityManager->flush();
            $entityManager->getConnection()->commit();

            $success = true;

            return $envelope;
        } catch (\Throwable $exception) {
            if ($exception instanceof HandlerFailedException) {
                // Remove all HandledStamp from the envelope so the retry will execute all handlers again.
                // When a handler fails, the queries of allegedly successful previous handlers just got rolled back.
                throw new HandlerFailedException($exception->getEnvelope()->withoutAll(HandledStamp::class), $exception->getWrappedExceptions());
            }

            throw $exception;
        } finally {
            $connection = $entityManager->getConnection();

            if (!$success && $connection->isTransactionActive()) {
                $connection->rollBack();
            }
        }
    }
}

Additional Context

No response

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

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.