@Scheduled runs a method on a fixed rate or cron expression, which is convenient for recurring work. In a multi-instance deployment, though, every instance runs the job, so coordination and overlap become the real concerns.
Before you start
You should be comfortable with beans and configuration. This article covers scheduling and its distributed pitfalls.
Step-by-step walkthrough
Step 1: Choose fixed rate or fixed delay
A fixed rate schedules the next run a set time after the previous start, which can overlap if the work is slow. A fixed delay waits a set time after the previous run finishes, which prevents overlap but drifts. Choose based on whether overlap is acceptable.
Step 2: Coordinate across instances
In a cluster, @Scheduled fires on every instance unless you guard it, so a job that sends emails would run N times. Use a distributed lock or a scheduler with leader election so only one instance runs the job.
Step 3: Keep jobs bounded and observable
Bound the work so a run finishes within its interval, log what it did, and handle errors so one failure does not silently stop the schedule. A job that throws repeatedly should be visible, not swallowed.
Worked scenario
A guard ensures only one instance runs the job.
@Scheduled(cron = "0 0 * * * *") // hourly
public void sendDigests() {
if (!lock.tryAcquire("digest-job", Duration.ofMinutes(5))) return;
try { digestService.sendAll(); }
finally { lock.release("digest-job"); }
}Walk through the example
The cron expression runs the method hourly on every instance, but the lock means only the instance that acquires it proceeds; the others return immediately. That keeps the digest from being sent once per instance. The lock is released in a finally, so a failure does not leave it held.
Common mistake
Assuming a scheduled method runs once in a cluster, which it does not, so jobs duplicate work. Another is a fixed-rate job that takes longer than its interval and overlaps itself.
Verify the behavior
Run two instances and confirm the guarded job executes once. Time a job longer than its interval under a fixed rate and observe the overlap, then switch to fixed delay. Confirm errors are logged rather than swallowed.
Interview exercise
Why can @Scheduled duplicate work in a cluster?
Answer and reasoning
Because the annotation registers the schedule in each application context, and every instance has its own, so each fires the job. Without coordination, a job like sending emails runs once per instance. A distributed lock or a leader-elected scheduler ensures a single execution.
Continue learning
Compare coordination in Leader election and async work in Async executor. Read the Spring scheduling documentation and try the Spring Boot interview questions.