- Ya
- 2 Septemba 2026, 02:43 UTC
- Mwandishi
- Kamo
- Ahadi ya
- 6906043
deleteByArticleUidAndLocale is a @Modifying query and JPA refuses to run one outside a transaction. Nothing on this path ever opened one, so every locale of every article threw TransactionRequiredException -- "Executing an update/delete query" -- which the loop caught per locale, logged at WARN, and moved past. The knowledge base has been serving English to every locale since the feature shipped, and the ten-minute sweep has been re-attempting the entire corpus forever because nothing it did ever stuck. Found by watching the logs during an import: 21 failures per article, every article, every retry. Each locale now runs in its own transaction, via TransactionTemplate rather than @Transactional on the method. The boundary has to be per locale -- one transaction around all 21 means a single failing locale rolls back the twenty that worked -- and a self-invoked helper would bypass the proxy in exactly the way that produced the @Async bug in this same file. The translate call itself stays outside the transaction. It is an HTTP request to another service with a 120-second read timeout, and holding a database connection across it would tie up the pool for the duration. Also: the async executor drops on saturation instead of running on the caller. CallerRunsPolicy is usually right, but the caller here is the Tomcat thread that just saved an article, and handing it 21 HTTP calls is the exact stall this work was moved off the request thread to avoid. The sweep is a real recovery path, not a hope -- deferring into it is not the same as dropping work on the floor.