A relay integration test must cross the same database and transport boundaries that a deployed worker crosses.
Spring relay integration tests: prove the boundaries H2 cannot
What the local suite proves
ScheduledOutboxPollerTest proves that Spring schedules a callback, the local H2 row is selected and claimed, a fake transport can fail once and retry, a batch cap leaves one row pending, and an already-applied event does not mutate stock twice. OutboxRelayFlowTest separately checks logical due times, parked work and token-fenced acknowledgement. Both suites run in one process.
Those facts do not establish two-worker claim fairness, broker persistence, broker redelivery, target-database isolation, shutdown drain or crash recovery. The scheduler lesson names the first boundary; the cut-point lesson names the duplicate boundary.
Next test matrix
Run two worker instances against the target database. Race claims for the same due row and assert one current token. Add a real transport test: confirm publish, kill the relay before acknowledgement, restart, then assert one business mutation. Inject a lost publish response, slow consumer, permanent payload rejection, expired lease and broker outage. Check row state and metrics after each cut point.
Keep test clocks controllable for exact due-time checks, then add a small number of real scheduling tests. Avoid sleeps as the only evidence. Use a latch or observable state with a deadline so failures are bounded and reproducible. The current scheduled fixture uses a latch; it does not replace a process-kill test.
Checked source
mvn -q -Dtest=ScheduledOutboxPollerTest,OutboxRelayFlowTest testVerification boundary
ScheduledOutboxPollerTest and OutboxRelayFlowTest run locally. The excerpt is shortened or a labelled design sketch; the source kit contains the complete checked fixture.
Costs and limits
No target database, broker, containerized multi-instance environment, process-kill setup or deployment probe is included in this source kit.
Common Mistakes
- Do not report H2 scheduling as broker delivery.
- Do not infer cross-node claim safety from one scheduler thread.
- Do not use an unbounded wait for an asynchronous assertion.
Read next
Spring TaskScheduler: poll committed outbox rows in the background, Spring scheduled relay: recover when the consumer commits before acknowledgement, Spring relay failure trace: inspect persisted state at each cut point, Spring project: turn the local outbox model into a measured relay.
Continue with lease race checks
Continue with Spring outbox claim race: one conditional UPDATE wins.
