-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MySQL + deadlock leads to SAVEPOINT DOCTRINE_x does not exist
#6651
Comments
I am not sure how related this issue is; but I experience the following. I get the same error related to the I am using symfony with doctrine. I have a symfony command that prepares the application. My installation command is pretty simple. I run:
If I put If I run the command twice, there is no error due to the fact that the migrations are already executed and up to date. Even if I add multiple new entities, persist and flush them there are no issues if I run the migrations first. This issue only occurs after I updated from I have create an repo to reproduce this issue: https://github.com/petermanders89/dbal-issue. This is repo created with When running the install command; in this case with |
hey @petermanders89 if using MySQL, you should try to declare your migrations as "non transactional". In MySQL, "ALTER TABLE" statements, and all other statements which modify the db structure implicitly closes the transaction. At the end, when doctrine commits the changes, it tries to commit a non-existent transaction, and your migration fails 💥 |
Hey @nikophil . Thank you! That indeed solves all my issues related to this. Sorry to mess up your issue. |
@nikophil please provide a sample script or other instructions that will reproduce your issue. Ideally, it should use only DBAL as a dependency. |
Hi @morozov here it is: https://github.com/nikophil/dbal-repro you can run it by:
I've somehow reproduced a concurrency problem by running twice The concurrency creates a deadlock. On my machine, I have a deadlock, and an error on rollback every time I'm running the script. The script outputs the error, basically:
as you can see, the rollback throws an error, and the problem occurs for both dbal 3 et 4 |
hey @morozov by any chance, did you check the reproducer I gave? Do you think we can fix this? I'd be willing to provide a PR, but I'd prefer that we agree on a solution first. thanks 🙏 |
@nikophil thanks for the reproducer. I was able to run it and observe the same behavior as described in the issue. The question is, why do you believe this is a bug? In my understanding, a nested transaction attempts to roll back to a savepoint. This savepoint no longer exists because the whole transaction in the session where it was previously created was rolled back as a victim of a deadlock. So the attempt fails, which is reported via an exception. This looks correct. If it doesn't matter to your business logic whether the transaction was rolled back to the savepoint or fully rolled back, why don't you catch this exception and do nothing? |
In my understanding, the underlying error (the deadlock) is hidden by the savepoint error, so it's quite hard to reason about the problem. |
So, if you're saying that "if a deadlock occurs in a nested transaction, a |
Yeah that's were I'd like to go :) But what should we do if a save point error occurs? But as far as I know this is only a mysql problem 🤔 |
If a savepoint error occurs due to a deadlock, it should throw a deadlock exception. From the API consumer's standpoint, there are no savepoints, there are nested transactions, and we need to tell all consumers that started a transaction at any level that their transaction was rolled back due to a deadlock. |
I'm wondering how this can be achieved, there is no way to know what was the reason why And always muting the error from any hints about this? |
That's for sure.
I'm not really familiar with transactions in DBAL, so I don't have any immediate hints, and there isn't necessary an easy solution to this. If I were to implement this, I'd start with a space-time diagram (like this) and document the current behavior. The actors there would be:
I'd documented the interaction between them in the form of method calls, returns and/or exceptions. Then it may become clear how the communication needs to change. |
well, it seems that it can't be fixed directly in the DBAL without a BC break 🤔 but maybe this can be mitigated in the callers. In my case, the component which starts the transactions is I think this could also be done in the ORM: here and here. Those are the same places where doctrine/orm#11230 and symfony/symfony#59103 fixed the previous error where a rollback error did hide the original error. any thoughts @greg0ire? |
@nikophil I'm not sure I understand the issue. Are you saying:
|
Bug Report
Summary
Hello,
this issue is a follow up of doctrine/orm#11230: in MySQL, when a deadlock occurs because of concurrency, the system tries to rollback, and then an error "SAVEPOINT DOCTRINE_x does not exist" occurs.
At first, the savepoint error did hide the original deadlock error. This has been fixed thanks to doctrine/orm#11646 - and this will soon be fixed as well in symfony/messenger.
Nevertheless, doctrine/orm#11230 has been closed, but the original problem is not fixed, and the rollback still fails, which results in closing the EM, and breaking the worker.
Since the dbal is the only one aware of savepoints, I think this should be fixed here.
Current behavior
When a deadlock occur, within a transaction with savepoints in MySQL, the rollback fails with
SAVEPOINT DOCTRINE_x does not exist
Expected behavior
No error on roll back 😅
From MySQL doc:
So maybe when a deadlock occurs, DBAL should be resilient when the rollback fails? Or it should check the existence of the given savepoint/transaction before rolling back?
The text was updated successfully, but these errors were encountered: