A PHP app on Symfony and Doctrine that shows how a database deadlock happens.
sh bin/build.sh
docker exec -it varfrog-deadlock-app sh bin/run.sh
We have two records of an entity \App\Entity\User
in the database with usernames "alice" and "bob" - let's call them
users Alice and Bob, respectively.
bin/run.sh launches two commands in parallel:
- app:lock-alice-and-bob - it first locks Alice, sleeps for some seconds, then tries to lock Bob,
- app:lock-bob-and-alice - it locks Bob and Alice, without sleeping.
This results in a deadlock in the 1st command.
Output of bin/run.sh
:
[error] Got a deadlock in app:lock-alice-and-bob
Command log in a chronological order, lines numbered in sequence:
1 19:56:39.622337;app:lock-alice-and-bob;Locking Alice and sleeping.
2 19:56:39.622344;app:lock-bob-and-alice;Locking Bob.
3 19:56:39.634649;app:lock-bob-and-alice;Locking Alice.
4 19:56:44.634883;app:lock-alice-and-bob;Locking Bob.
5 19:56:44.640286;app:lock-alice-and-bob;Got a deadlock.
Explanation of the log:
- Lines 1, 2: the order of these lines does not matter - either of the commands can be started first. Here,
app:lock-alice-and-bob
locks Alice and sleeps for some seconds,app:lock-bob-and-alice
locks Bob. - Line 3:
app:lock-bob-and-alice
tries to get a lock on Alice but has to wait since it's locked in line 1 byapp:lock-alice-and-bob
- Line 4:
app:lock-alice-and-bob
tries to get a lock on Bob but it has to wait forapp:lock-bob-and-alice
to end its database transaction, i.e. for the lock on Bob to be released. But nowapp:lock-bob-and-alice
will never release the lock because it itself is waiting for the same thing - it waits for a lock of Alice to be released byapp:lock-alice-and-bob
(it's blocking in line 3). This situation cannot be resolved (both commands are infinitely waiting for each other) and thus we get a deadlock (Line 5).