BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Scheduling and batch

Spring

@Scheduled jobs

@Scheduled runs a method repeatedly on a timer: at a fixed rate, with a fixed delay between runs, or on a cron schedule.

Learn these first

At a glance

Mental model

An alarm clock built into a method.

What happens, in order
  1. 1@EnableScheduling turns the feature onA method with @Scheduled and no arguments is then called by a scheduler thread.
  2. 2fixedRate = 5000 starts a run every 5 seconds, counted from the previous startfixedDelay = 5000 waits 5 seconds after the previous run finished. cron = "0 0 2 * * *" uses a Spring cron expression with six fields (seconds first).
  3. 3The default scheduler has a single thread, so a slow job delays every other scheduled method in the application
  4. 4zone = "Asia/Kolkata" sets the time zone for cron expressionsWithout it the server's default zone applies, which changes between your laptop and a UTC server.
Remember
Watch out
Running a once-a-night job on multiple replicas without a lockA long job blocking all other scheduled methods on the single default threadIgnoring time zones and DSTUsing fixedRate for work that can exceed its interval
Example (highlighted lines explain it)
@Componentpublic class NightlyJob {    @Scheduled(cron = "0 0 2 * * *", zone = "UTC")    public void run() {        log.info("Starting nightly export");        exporter.exportAll();    }}
  1. line 3 uses Scheduled, the core of @Scheduled jobs
Read the full explanation (about 2 min)

@Scheduled runs a method repeatedly on a timer: at a fixed rate, with a fixed delay between runs, or on a cron schedule. Every running instance of the application runs it.

A mental model

An alarm clock built into a method. It rings on a schedule whether or not you are ready, and if the app is deployed on three servers, three alarms ring.

How it works

@EnableScheduling turns the feature on. A method with @Scheduled and no arguments is then called by a scheduler thread.

fixedRate = 5000 starts a run every 5 seconds, counted from the previous start. fixedDelay = 5000 waits 5 seconds after the previous run finished. cron = "0 0 2 * * *" uses a Spring cron expression with six fields (seconds first).

The default scheduler has a single thread, so a slow job delays every other scheduled method in the application.

zone = "Asia/Kolkata" sets the time zone for cron expressions. Without it the server's default zone applies, which changes between your laptop and a UTC server.

Going deeper

With several instances (Kubernetes replicas, multiple servers) each one fires the job. For work that must happen once, use a distributed lock such as ShedLock, a database row lock, or move the job to a single-replica deployment or a Kubernetes CronJob.

fixedRate jobs that take longer than the interval do not run in parallel on the default scheduler; they queue and bunch up. Prefer fixedDelay unless you need a steady cadence.

Exceptions thrown from a scheduled method are logged and the schedule continues, so a job can fail every night without anyone noticing unless you add alerting.

Daylight saving time can make a 02:30 job skip a day or run twice. Prefer UTC for important schedules.

Under the hood

A ScheduledAnnotationBeanPostProcessor finds annotated methods when beans are created and registers them with a TaskScheduler (ThreadPoolTaskScheduler, pool size 1 by default). The cron expression is parsed by CronExpression, which computes the next fire time.

Common mistakes

  • Running a once-a-night job on multiple replicas without a lock.
  • A long job blocking all other scheduled methods on the single default thread.
  • Ignoring time zones and DST.
  • Using fixedRate for work that can exceed its interval.

How Unravel recognises it

When you paste code, Unravel looks for these signs of @scheduled jobs. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is @Scheduled jobs?

@Scheduled runs a method repeatedly on a timer: at a fixed rate, with a fixed delay between runs, or on a cron schedule. Every running instance of the application runs it.

What are the most common mistakes with @Scheduled jobs?

Running a once-a-night job on multiple replicas without a lock. A long job blocking all other scheduled methods on the single default thread. Ignoring time zones and DST. Using fixedRate for work that can exceed its interval.

How can I see @Scheduled jobs in real code?

Paste your own Java into Unravel and it will point out where @scheduled jobs appears, explain how it works at the detail level you choose, and draw the flow of the code around it.