How does Restate help?
Restate has many features that make it a good fit for implementing cron jobs:- Durable timers: Schedule tasks reliably for future execution.
- Task resiliency: Automatic retries until success.
- Task control: Inspect and cancel running jobs.
- K/V state: Store and query cron job details using K/V storage.
- FaaS support: Integrates with platforms like AWS Lambda, scaling to zero when idle.
- Scalability: Handles many parallel jobs; scales horizontally.
- Observability: View execution history and job status in the Restate UI.
Example
To implement cron jobs, you can copy over the following file (TS / Java / Go) to your project:CronJobInitiator
Service, and a CronJob
Virtual Object:

- Send requests to
CronJobInitiator.create()
to start new jobs with standard cron expressions:
- Each job gets a unique ID and runs as a CronJob Virtual Object.
- Jobs automatically reschedule themselves after each execution.
Running the example
1
Download the example
2
Start the Restate Server
3
Start the Service
4
Register the services
5
Send a request
For example, run For example, or run You can also use the cron service to execute handlers on Virtual Objects, by specifying the Virtual Object key in the request.You will get back a response with the job ID.Using the job ID, you can then get information about the job:Or cancel the job later:
executeTask
every minute:executeTask
at midnight:6
Check the scheduled tasks and state
In the UI, you can see how the tasks are scheduled, and how the state of the cron jobs is stored in Restate.

You can kill and restart any of the services or the Restate Server, and the scheduled tasks will still be there.


Adapt to your use case
Note that this implementation is fully resilient, but you might need to make some adjustments to make this fit your use case:- Take into account time zones.
- Adjust how you want to handle tasks that fail until the next task gets scheduled. With the current implementation, you would have concurrent executions of the same cron job (one retrying and the other starting up).
If you want to cancel the failing task when a new one needs to start, you can do the following: at the beginning of the
execute
call, retrieve thenext_execution_id
from the job state and check if it is completed by attaching to it with a timeout set to 0. If it is not completed, cancel it and start the new iteration.