Drizzle is a Elixir application to schedule repeated tasks.
- Cron notation
- Seconds resolution
- Time zone support per job
- Jobs can be updated during runtime
- Fast-forward of time spend offline due to restarts
This basic example tells Drizzle to output "hello" every second:
config :drizzle,
records: [%{
crontab: "* * * * * *",
time_zone: :utc,
module: IO,
function: :puts,
args: ["hello"]
}]Each record consist of different fields:
crontab: defines when a job is run (details here)timezone: either:utcor a time zone like "Europe/Berlin"module,function,args: what will be called when the matching time has come
Here is a more involved example:
config :elixir, :time_zone_database, Tz.TimeZoneDatabase
config :drizzle,
records: [%{
crontab: "0 20 * * Sat",
time_zone: "Australia/Adelaide",
module: IO,
function: :puts,
args: ["cheers from down under"]
}],
last_evaluation: (case File.read("/tmp/drizzle_time") do {:error, _} -> nil; {:ok, time} -> String.to_integer(time) end),
evaluation_time_fun: fn(time) -> File.write!("/tmp/drizzle_time", inspect(time)) endHere we are greeting every Saturday at 8pm Australian Central Standard Time. Please note that you need to configure a time zone DB to do this.
These keys are optional:
last_evaluation: the last known input toevaluation_time_fun(see below)evaluation_time_fun: a function to store the time stamp of the last evaluation (see below)
Drizzle counts time in Gregorian seconds (as in DateTime.utc_now |> DateTime.to_gregorian_seconds |> elem(0)). The problem is that when the application is stopped for restarts or upgrades, some seconds might not be observed. If you use evaluation_time_fun to capture and store this time, you can later pass it to last_evaluation so Drizzle can catch up and potentially trigger jobs that where scheduled while it was out.
evaluation_time_fun will be called whenever a job is executed and every 30 seconds.
You can update the cron tab at runtime:
Drizzle.update([%{ crontab: "* * * * * *", time_zone: :utc, module: IO, function: :puts, args: ["olleh"] }])
Drizzle evaluates the cron tab for each second. On a modern machine evaluating one year (31536000 seconds) for one cron tab line takes about 30 CPU seconds.
Drizzle tries to trigger jobs as early during the corresponding second as possible but there are no guarantees. Under heavy load, triggering might be delayed due to how scheduling works in the BEAM.
Here are typical times for triggers between 0.8ms and 16ms after the second:
~U[2026-06-01 06:10:18.003031Z]
~U[2026-06-01 06:10:19.001435Z]
~U[2026-06-01 06:10:20.001111Z]
~U[2026-06-01 06:10:21.004924Z]
~U[2026-06-01 06:10:22.000842Z]
~U[2026-06-01 06:10:23.001319Z]
~U[2026-06-01 06:10:24.016850Z]
~U[2026-06-01 06:10:25.001041Z]
~U[2026-06-01 06:10:26.000944Z]
~U[2026-06-01 06:10:27.001133Z]
~U[2026-06-01 06:10:28.001860Z]
~U[2026-06-01 06:10:29.000957Z]
~U[2026-06-01 06:10:30.000943Z]
~U[2026-06-01 06:10:31.000732Z]If available in Hex, the package can be installed
by adding drizzle to your list of dependencies in mix.exs:
def deps do
[
{:drizzle, "~> 0.1.0"}
]
endDocumentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/drizzle.