# Clockwork
[](https://hex.pm/packages/clockwork)
[](https://hexdocs.pm/clockwork/)
A robust cron-like job scheduling library for Gleam, designed for reliability and ease of use.
## Features
- **Cron Expression Support**: Parse standard cron expressions or build them programmatically
- **Flexible Scheduling**: Schedule jobs to run at specific times using cron expressions
- **Timezone Support**: Configure jobs to run in specific timezones
- **Logging & Telemetry**: Built-in logging and OpenTelemetry integration
- **Simple API**: Functional, builder-style interface for job configuration
## Installation
```sh
gleam add clockwork
```
## Quick Start
```gleam
import clockwork
import clockwork/schedule
import gleam/erlang/process
import gleam/io
import gleam/time/duration
pub fn main() {
// Create a cron schedule that runs every minute
let assert Ok(cron) = "* * * * *" |> clockwork.from_string
// Define a job function
let job = fn() {
io.println("This job runs every minute!")
Nil
}
// Create and configure a scheduler
let scheduler = schedule.new("minutely-job", cron, job)
|> schedule.with_logging()
|> schedule.with_telemetry()
// Start the scheduler
let assert Ok(running_schedule) = schedule.start(scheduler)
// Keep the process running
process.sleep_forever()
}
```
## Cron Expressions
Clockwork supports standard cron expressions with five fields:
```
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
│ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) (0 is Sunday)
│ │ │ │ │
* * * * *
```
Common patterns:
- `* * * * *` - Every minute
- `0 * * * *` - Every hour, on the hour
- `0 0 * * *` - Every day at midnight
- `0 12 * * 1-5` - Weekdays at noon
- `*/15 * * * *` - Every 15 minutes
- `0 0 1,15 * *` - 1st and 15th of each month at midnight
You can also build cron expressions programmatically:
```gleam
// Create a cron schedule using the builder pattern
let cron = clockwork.default()
|> clockwork.with_minute(clockwork.every(15))
|> clockwork.with_hour(clockwork.exactly(at: 0))
|> clockwork.with_day(clockwork.list([
clockwork.exactly(at: 1),
clockwork.exactly(at: 15)
]))
|> clockwork.with_month(clockwork.ranging(from: 5, to: 10))
|> clockwork.with_weekday(clockwork.ranging_every(2, from: 2, to: 6))
```
## Scheduling Jobs
The `schedule` module provides a builder-style API for configuring and running jobs:
```gleam
// Create a new scheduler with a unique ID, cron expression and job function
let scheduler = schedule.new("job-id", cron_expression, job_function)
// Enable optional features using builder methods
let configured_scheduler = scheduler
|> schedule.with_logging() // Enable logging
|> schedule.with_telemetry() // Enable OpenTelemetry integration
|> schedule.with_time_offset( // Run in US Eastern Time
duration.hours(-5)
)
// Start the scheduler
let result = schedule.start(configured_scheduler)
// Later, stop a running job
case result {
Ok(running_job) -> schedule.stop(running_job)
Error(_) -> io.println("Failed to start job")
}
```
## Timezone Support
Jobs can be configured to run in specific timezones by setting a time offset:
```gleam
// Run jobs in local timezone
let local_job = schedule.new("local-job", cron, job)
|> schedule.with_time_offset(calendar.local_offset())
// Run jobs in a specific timezone (e.g., UTC+2)
let berlin_job = schedule.new("berlin-job", cron, job)
|> schedule.with_time_offset(duration.hours(2))
```
## Telemetry Integration
Clockwork integrates with OpenTelemetry to provide observability for your scheduled jobs:
```gleam
// Enable telemetry for a job
let observable_job = schedule.new("tracked-job", cron, job)
|> schedule.with_telemetry()
```
This will create spans for each job execution with detailed information about the job's timing and execution context.
## Practical Example: Daily Report Generator
```gleam
import clockwork
import clockwork/schedule
import gleam/erlang/process
import gleam/io
import gleam/time/calendar
import gleam/time/duration
pub fn main() {
// Create a cron schedule for midnight every day
let assert Ok(cron) = "0 0 * * *" |> clockwork.from_string
// Define the report generation job
let generate_daily_report = fn() {
io.println("Generating daily report...")
// Report generation code would go here
io.println("Daily report completed!")
Nil
}
// Create and configure the scheduler
let scheduler = schedule.new(
"daily-report-generator",
cron,
generate_daily_report
)
|> schedule.with_logging()
|> schedule.with_time_offset(calendar.local_offset())
// Start the scheduler
let assert Ok(running_schedule) = schedule.start(scheduler)
io.println("Daily report scheduler started!")
process.sleep_forever()
}
```
## Documentation
For detailed documentation, visit [HexDocs](https://hexdocs.pm/clockwork/).
## Development
```sh
gleam run # Run the project
gleam test # Run the tests
gleam format # Format the code
```
## License
Clockwork is licensed under the MIT License.