Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring TaskScheduler: poll committed outbox rows in the background

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A scheduled outbox worker runs a bounded polling callback after the producer has committed work.

Download Spring source kit

The checked worker

The source kit creates a ThreadPoolTaskScheduler with one thread and schedules a poll every 20 milliseconds after the previous callback finishes. The test inserts EVENT-41, waits on a latch for the callback to acknowledge it, then cancels the scheduled future and shuts the scheduler down. A local consumer transaction changes SKU-29 from 10 to 7. The row ends DELIVERED.

Fixed delay measures from the end of one invocation to the start of the next. It does not mean that each event completes inside 20 milliseconds. The batch budget stops one invocation from draining an unlimited backlog. A guarded claim still matters when more than one process runs; one scheduler thread is not a distributed lock.

Keep the boundary visible

The transport in this fixture is a Java callback, not a broker. The scheduler is started inside a JUnit test, not installed in ReceiptApplication. It uses an in-memory H2 database and wall-clock due times. A process kill loses that database in this fixture, so the test does not establish restart recovery.

When installed in a service, configure pool size, poll interval, exception reporting and shutdown as deployment settings. Keep the remote call outside the producer transaction. The transaction lesson explains why the two commits cannot be one local atomic step.

Checked source

Java
var future = scheduler.scheduleWithFixedDelay(
    () -> new Poller(this::consumeLocally, delivered::countDown).runBatch(1),
    Duration.ofMillis(20));
assertTrue(delivered.await(3, TimeUnit.SECONDS));
future.cancel(false);
scheduler.shutdown();

Verification boundary

ScheduledOutboxPollerTest.scheduledWorkerConsumesCommittedRowAndStops. The excerpt is shortened or a labelled design sketch; the source kit contains the complete checked fixture.

Costs and limits

The test uses one scheduler thread and a three-second latch bound. It does not measure production poll latency, cross-node claims, durable recovery, or broker acceptance.

Common Mistakes

  • Do not call a scheduler thread a durable queue.
  • Do not put unbounded work into a fixed-delay callback.
  • Do not leave a test-created scheduler running after the assertion.

Read next

Spring outbox polling: cap work per tick and measure backlog age, Spring TaskScheduler shutdown: stop new polls and account for in-flight work, Spring outbox claims: lease expiry and token-fenced acknowledgement, Spring outbox transaction boundaries: where atomicity ends, Spring outbox relay: claim, deliver, and acknowledge one event.

spring
spring-boot
scheduled-relay
Storage details