TIL:
With the database cache, if the previous lock is still there, Laravel tries an INSERT, catches the duplicate key, then falls back to an UPDATE.
On MySQL, fine. On Postgres, a failed statement poisons the whole transaction:
So posting twice in a row = 500, and your commit is gone 💀
The fix is one line:
Bonus: your tests never catch it, because RefreshDatabase wraps every test in a transaction and the cache store is "array" in phpunit.xml. I only reproduced it on a real Postgres with no test transaction around.
Fix incoming for https://github.com/dev-null-sh/dev-null.sh/issues/1066 👀
->afterCommit() doesn't make a unique job wait for the commit. Only the job waits. Its lock is taken at dispatch.
php
DB::transaction(function () use ($user) { // ...save the commit dispatch(new CheckUserLevel($user))->afterCommit(); // ShouldBeUnique });
SQLSTATE[25P02]: current transaction is aborted, commands ignored until end of transaction block
php
DB::afterCommit(fn () => dispatch(new CheckUserLevel($user)));
GitHubSecond approved commit 500s while CheckUserLevel still holds its unique-job lock · Issue #1066 · dev-null-sh/dev-null.shWhat happens A user posts an approved commit. Within the lock window of the previous one, their next approved commit returns 500. Log line: SQLSTATE[25P02]: In failed sql transaction: 7 ERROR: curr...
commit b5784bd