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

Spring @Scheduled on three replicas: the callback runs three times

Last updated: 1 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

@Scheduled arranges callbacks in each application context; it does not elect a cluster-wide worker.

Count application instances

When three parcel-service replicas all contain the same scheduled relay bean, each replica wakes on its own timer. A single-node test sees one call and can hide three-way production execution. Make the database claim the arbiter: atomically select due rows for one owner, retain a lease, and fence stale acknowledgments. The schedule merely asks each process to look for work.

Avoid overlapping local runs

A fixed-rate trigger can fire again while a slow previous run is still active if the scheduler has capacity. Use bounded claims and a local concurrency guard where needed, but keep the database lease because local guards cannot coordinate other replicas. The outbox worker supplies the state machine; shutdown handling explains why a lease may outlive a worker.

Prove handoff

Run three app instances against one database, pause the current owner after claim, and let its lease expire. Confirm a second owner takes over and the old owner cannot commit an acknowledgment. A test of only the @Scheduled method invocation cannot establish cluster safety.

Implementation sketch

Java
@Scheduled(fixedDelayString = "${parcel.relay.delay.ms:7000}")
public void dispatchDueParcels() {
    for (ClaimedParcel parcel : claims.claimDue(23)) {
        relay.sendAndAcknowledge(parcel);
    }
}

Cost and verification

Every replica polls, adding database reads when idle. Small bounded claims and a suitable interval trade latency for load; leases require a clock and expiration policy.

Common Mistakes

  • Do not treat @Scheduled as a cluster leader election mechanism.
  • Do not hold a local mutex and assume other replicas cannot run.
  • Do not acknowledge work after losing the lease or fencing token.

Read next

Spring TaskScheduler: poll committed outbox rows in the background, Spring outbox claims: lease expiry and token-fenced acknowledgement, Outbox acknowledgements: require the current lease token, Spring TaskScheduler shutdown: stop new polls and account for in-flight work.

spring
spring-boot
scheduled
scheduled-worker-multi-instance
Storage details