When a RetryableException is thrown, entitymanager should not be closed #5404

Open
opened 2026-01-22 15:06:52 +01:00 by admin · 5 comments
Owner

Originally created by @kcassam on GitHub (Feb 1, 2017).

When a RetryableException is thrown, entitymanager should not be closed

The "bad" code is here : https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/UnitOfWork.php#L400

RetryableException are DeadlockException and LockWaitTimeoutException

entitymanager should not be closed so we can retry the flush like that

/*
    * Since doctrine 2.6, you cannot retry a flush when an exception had appeared 
    * because the entity manager is closed and all entities detach, even with a RetryableException. 
    * This function won't work, bescause if there is an Exception, the em is closed. 

    private retryflush() {

        $retry = 0;
        while ($retry < 3) {
            try {
                $this->em->flush();
                return;
            } catch (RetryableException $e) {
                
                if ($retry >= 2) {
                    throw $e;
                }
                sleep(1);
                $this->reset();
                $retry++;
            } 
        }
    }
*/

Originally created by @kcassam on GitHub (Feb 1, 2017). When a RetryableException is thrown, entitymanager should not be closed The "bad" code is here : https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/UnitOfWork.php#L400 RetryableException are DeadlockException and LockWaitTimeoutException entitymanager should not be closed so we can retry the flush like that ``` /* * Since doctrine 2.6, you cannot retry a flush when an exception had appeared * because the entity manager is closed and all entities detach, even with a RetryableException. * This function won't work, bescause if there is an Exception, the em is closed. private retryflush() { $retry = 0; while ($retry < 3) { try { $this->em->flush(); return; } catch (RetryableException $e) { if ($retry >= 2) { throw $e; } sleep(1); $this->reset(); $retry++; } } } */ ```
admin added the New Feature label 2026-01-22 15:06:52 +01:00
Author
Owner

@jaikdean commented on GitHub (Aug 9, 2019):

Is there a good approach to retrying after deadlocks in the meantime?

@jaikdean commented on GitHub (Aug 9, 2019): Is there a good approach to retrying after deadlocks in the meantime?
Author
Owner

@tinpansoul commented on GitHub (Oct 11, 2019):

Is there any "at least not so bad" and simple/quick solution before v3.x release?

For example, i have merge in loop and then make one flush with hundreds entities. But if there is any exception inside of loop – a lot of changes inside loop are lost with log flooded by "EntityManager is closed". That's annoying.

Any solutions can be done here now except making flush/reset inside of loop (super bad idea) or level down to detach from orm and use raw dbal/sql queries?

@tinpansoul commented on GitHub (Oct 11, 2019): Is there any "at least not so bad" and **simple/quick** solution before v3.x release? For example, i have `merge` in loop and then make one `flush` with hundreds entities. But if there is any exception inside of loop – a lot of changes inside loop are lost with log flooded by "EntityManager is closed". That's annoying. Any solutions can be done here now except making `flush`/`reset` inside of loop (super bad idea) or level down to `detach` from orm and use raw dbal/sql queries?
Author
Owner

@SenseException commented on GitHub (Oct 15, 2019):

Approaches were mentioned in #865, but it still will be an entity manager without persisted entities.

@SenseException commented on GitHub (Oct 15, 2019): Approaches were mentioned in #865, but it still will be an entity manager without persisted entities.
Author
Owner

@dvdknaap commented on GitHub (Oct 6, 2021):

Is there already someone that found a solutions for this because impossible to retry it even when you reset the manager ?

The only solution is to do the full request again in rabbitMQ till it's working.

@dvdknaap commented on GitHub (Oct 6, 2021): Is there already someone that found a solutions for this because impossible to retry it even when you reset the manager ? The only solution is to do the full request again in rabbitMQ till it's working.
Author
Owner

@rixafy commented on GitHub (Feb 23, 2025):

Is there already someone that found a solutions for this because impossible to retry it even when you reset the manager ?

The only solution is to do the full request again in rabbitMQ till it's working.

I wrote entity manager that can do this https://gist.github.com/Rixafy/82d96712cf1f87ce26ce052ced2eba78.

I did it by copying UnitOfWork before flush() or wrapInTransaction is called on real EM, then when RetryableException is thrown, I'll check if EM is closed, and if it is, I'll reopen it using reflection and set the original copy of UnitOfWork, because closing EM also cleared unit of work state, so far it's working alright, I had 2 deadlocks today and both succeeded on 2. attempt.

@rixafy commented on GitHub (Feb 23, 2025): > Is there already someone that found a solutions for this because impossible to retry it even when you reset the manager ? > > The only solution is to do the full request again in rabbitMQ till it's working. I wrote entity manager that can do this https://gist.github.com/Rixafy/82d96712cf1f87ce26ce052ced2eba78. I did it by copying UnitOfWork before flush() or wrapInTransaction is called on real EM, then when RetryableException is thrown, I'll check if EM is closed, and if it is, I'll reopen it using reflection and set the original copy of UnitOfWork, because closing EM also cleared unit of work state, so far it's working alright, I had 2 deadlocks today and both succeeded on 2. attempt.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#5404