clockwork_schedule
clockwork_schedule
A scheduling extension for the Clockwork library that provides a way to define and manage recurring tasks with built-in OTP supervision support.
This module allows you to:
- Schedule tasks using cron expressions
- Run tasks under OTP supervision for fault tolerance
- Configure time zones with UTC offsets
- Enable logging for monitoring job execution
- Gracefully start and stop scheduled tasks
Basic Usage
import clockwork
import clockwork_schedule
import gleam/erlang/process
pub fn main() {
let assert Ok(cron) = clockwork.from_string("*/5 * * * *")
let scheduler = clockwork_schedule.new("my_task", cron, fn() { io.println("Hello!") })
let name = process.new_name("my_task")
let assert Ok(_subject) = clockwork_schedule.start(scheduler, name)
// Task runs every 5 minutes until stopped
clockwork_schedule.stop(name)
}
Types
Internal message types used by the scheduler actor.
Run: Triggers the execution of the scheduled jobStop: Gracefully stops the scheduler
pub type Message {
Run
Stop
}
Constructors
-
Run -
Stop
Configuration for a scheduled task.
A Scheduler contains all the information needed to run a recurring task:
- An identifier for logging and debugging
- A cron expression defining when to run
- The job function to execute
- Optional logging configuration
- Optional time zone offset
Use the builder pattern to configure schedulers:
import gleam/erlang/process
let scheduler =
clockwork_schedule.new("backup", cron, backup_fn)
|> clockwork_schedule.with_logging()
|> clockwork_schedule.with_time_offset(tokyo_offset)
let name = process.new_name("backup")
let assert Ok(_subject) = clockwork_schedule.start(scheduler, name)
pub opaque type Scheduler
Values
pub fn new(
id: String,
cron: clockwork.Cron,
job: fn() -> Nil,
) -> Scheduler
Creates a new scheduler configuration.
Parameters
id: A unique identifier for this scheduler (used in logging)cron: A cron expression defining when the job should runjob: The function to execute on each scheduled occurrence
Example
import clockwork
let assert Ok(cron) = clockwork.from_string("0 */2 * * *") // Every 2 hours
let scheduler = clockwork_schedule.new("data_sync", cron, fn() {
database.sync_remote_data()
})
pub fn start(
scheduler: Scheduler,
name: process.Name(Message),
) -> Result(
actor.Started(process.Subject(Message)),
actor.StartError,
)
Starts an unsupervised scheduler.
This function starts a scheduler as a standalone actor that will run
according to its cron expression. For production use, prefer supervised
to run the scheduler under OTP supervision for better fault tolerance.
Parameters
scheduler: The scheduler configuration to startname: A unique name for the scheduler process
Returns
Ok(Subject(Message)): A subject to send messages to the schedulerError(actor.StartError): If the scheduler fails to start
Example
import clockwork
import clockwork_schedule
import gleam/erlang/process
pub fn main() {
let assert Ok(cron) = clockwork.from_string("*/30 * * * *") // Every 30 minutes
let scheduler =
clockwork_schedule.new("metrics", cron, fn() {
metrics.collect_and_report()
})
|> clockwork_schedule.with_logging()
let name = process.new_name("metrics")
let assert Ok(_subject) = clockwork_schedule.start(scheduler, name)
// The scheduler is now running
// Stop it when done:
clockwork_schedule.stop(name)
}
Note
The scheduler will continue running until explicitly stopped with stop
or until the process crashes. For automatic restart on failure, use
supervised instead.
pub fn stop(name: process.Name(Message)) -> Nil
Gracefully stops a running scheduler.
Sends a stop message to the scheduler, which will:
- Cancel any pending job executions
- Log a stop message (if logging is enabled)
- Terminate the scheduler actor
Parameters
name: The name of the scheduler process to stop
Example
import gleam/erlang/process
let name = process.new_name("my_scheduler")
let assert Ok(_subject) = clockwork_schedule.start(scheduler, name)
// Run for some time...
process.sleep(60_000) // 1 minute
// Gracefully stop
clockwork_schedule.stop(name)
Note
After calling stop, the scheduler will terminate. To restart scheduling,
create and start a new scheduler with a new name.
pub fn supervised(
scheduler: Scheduler,
name: process.Name(Message),
) -> supervision.ChildSpecification(process.Subject(Message))
Creates a child specification for running the scheduler under OTP supervision.
This is the recommended way to run schedulers in production. The scheduler will be automatically restarted if it crashes, ensuring your scheduled tasks remain reliable.
Parameters
scheduler: The scheduler configurationname: A unique name for the scheduler process
Returns
A supervision.ChildSpec that can be added to your supervision tree.
Example
import clockwork
import clockwork_schedule
import gleam/erlang/process
import gleam/otp/static_supervisor as supervisor
pub fn main() {
let assert Ok(cron) = clockwork.from_string("0 * * * *") // Every hour
let scheduler =
clockwork_schedule.new("hourly_task", cron, fn() {
perform_hourly_maintenance()
})
|> clockwork_schedule.with_logging()
// Create a unique name for the scheduler
let name = process.new_name("hourly_task")
// Create the child spec
let schedule_child_spec =
clockwork_schedule.supervised(scheduler, name)
// Add to supervision tree
let assert Ok(_sup) =
supervisor.new()
|> supervisor.add(schedule_child_spec)
|> supervisor.start()
// The scheduler is now running under supervision
// Control it using the name:
// clockwork_schedule.stop(name)
process.sleep_forever()
}
Fault Tolerance
If the scheduler crashes, the supervisor will automatically restart it. The new instance will recalculate the next occurrence and continue scheduling jobs as expected.
pub fn with_logging(scheduler: Scheduler) -> Scheduler
Enables logging for the scheduler.
When logging is enabled, the scheduler will log:
- When a job starts executing (with timestamp)
- When the scheduler is stopped
Logging uses the logging library and outputs at the Info level.
Example
let scheduler =
clockwork_schedule.new("cleanup", cron, cleanup_fn)
|> clockwork_schedule.with_logging() // Enable logging
pub fn with_time_offset(
scheduler: Scheduler,
offset: duration.Duration,
) -> Scheduler
Sets a time zone offset for the scheduler.
By default, schedulers use the system’s UTC offset. Use this function to run scheduled tasks in a specific time zone.
Parameters
scheduler: The scheduler to configureoffset: The UTC offset as a Duration (positive for east, negative for west)
Example
import gleam/erlang/process
import gleam/time/duration
// Configure for UTC+9 (Tokyo)
let tokyo_offset = duration.from_hours(9)
let tokyo_scheduler =
clockwork_schedule.new("tokyo_job", cron, job_fn)
|> clockwork_schedule.with_time_offset(tokyo_offset)
let tokyo_name = process.new_name("tokyo_job")
let assert Ok(_subject) = clockwork_schedule.start(tokyo_scheduler, tokyo_name)
// Configure for UTC-5 (New York)
let ny_offset = duration.from_hours(-5)
let ny_scheduler =
clockwork_schedule.new("ny_job", cron, job_fn)
|> clockwork_schedule.with_time_offset(ny_offset)
let ny_name = process.new_name("ny_job")
let assert Ok(_subject) = clockwork_schedule.start(ny_scheduler, ny_name)