- Shipped
- August 20, 2026 at 10:43 PM UTC
- Author
- Kamo
- Commit
- 309f6fc
storePayload saved the payload and then bumped totalReceived/lastReceivedAt by dirtying the endpoint entity — in the same transaction. Every submission to an endpoint hits the SAME endpoint row, and a dirty-entity save rewrites all fourteen columns, so two concurrent POSTs collided on YugabyteDB with 40001 could not serialize access due to concurrent update and the loser's transaction died — taking the payload insert with it. The submitter got {"status":"error"} and the lead was simply gone. A webhook meant to take third-party traffic could not take two requests at once: posting a farm list at concurrency 6 lost ~55% of it. Split so the lead never depends on the statistic: - storePayload persists only the payload, - recordReceipt/recordProcessed bump a single column via a targeted @Modifying update in their own transaction, and callers swallow their failures. They must be called from another bean — a self-invocation would rejoin the caller's transaction and reintroduce the coupling (see the self-invocation trap).