- Ya
- 27 Agosti 2026, 09:09 UTC
- Mwandishi
- Kamo
- Ahadi ya
- 31379b6
It was a method on ExchangeQueryService annotated @Transactional(REQUIRES_NEW), called from two private helpers on the same class. Spring's transaction advice lives on a proxy and a self-invocation never reaches it, so the annotation did nothing at all: the row joined the caller's transaction. That is precisely backwards for what it records. A FAILED outbound query would have rolled back the record of its own failure — and "we asked and they refused" is the row somebody investigating a gap in a patient's history actually needs. A ledger of only the successful queries answers the easy question and loses the hard one. Worse still, discover() and queryDocuments() are readOnly = true, so the write had no business being in their transaction at all. Extracted to ExchangeRequestRecorder, a bean of its own, exactly as BulkExportJobState was earlier for the same reason. A unit test cannot catch this — constructing the service directly means there is no proxy either, which is why it passed while being wrong. So the guard is structural: the recorder's test asserts the method is PUBLIC (a non-public method is never proxied, making its annotation inert) and that its propagation is REQUIRES_NEW. Both halves are invisible at a call site and both have to hold.