A Loop That Looked Efficient
The enrichment passes did the sensible thing. For each candidate row: write what we know, make the network call, write the result. Commit once at the end, because committing per row is more fsyncs and everyone knows batching is faster.
In a single-writer database, an uncommitted write holds the write lock. So the first update in that loop took the lock, and the very next statement was a network call. The lock was then held across every remaining fetch in the round — measured at roughly nine seconds for one pass, well past the configured busy timeout.
The Symptom Was in an Unrelated Feature
Nothing in the enrichment pass reported a problem. The failure surfaced somewhere else entirely: during a round, a reader pressing like or save got a locked-database error. And because the client's event handler caught errors broadly and just reloaded the shelf, the tap simply vanished — no message, no retry, the button just did not appear to work.
Three properties made this hard to find. It is intermittent, occurring only during rounds. It appears in a feature that has nothing to do with the code responsible. And the error was swallowed by a catch-all one layer away from where anyone would look.
Commit Per Row
The fix is one line moved inside the loop. Each row's update commits before its network call, so the lock is held for microseconds rather than seconds. The batching intuition was simply wrong for this shape of work: the cost being optimized was a handful of fsyncs, and the cost being paid was every concurrent writer in the process.
The general rule is worth stating without the database specifics: the duration of a lock should be bounded by computation you control, never by a remote system's response time. Any await, any request, any subprocess between acquiring and releasing turns your latency budget over to somebody else's server.
Test the Property, Not the Pass
The pass had tests and they passed, because they ran alone. The test that catches this asserts a property about concurrency: while a round is running, an ordinary write still succeeds. That is a different kind of test — it needs the pass and a writer in flight at the same time — and it is the only kind that could have found this.