mule
gleam add mule
import gleam/erlang/process
import gleam/time/duration
import mule.{MuleSpec}
import mule/engines/in_memory
import mule/jobs/worker
import mule/jobs/worker_registry
import mule/notifiers/isolated
pub fn main() -> Nil {
// A worker is a named function Mule runs, with a codec for its typed args.
let say_hello =
worker.new(
"say_hello",
perform: fn(_args, _job) {
// ... do the work ...
worker.Completed
},
codec: worker.nil_codec(),
)
// Choose a driver. Here: the in-memory engine + in-process notifier (no
// database). The caller starts and owns the engine's backing actor.
let assert Ok(storage) = in_memory.start()
let notifier_name = process.new_name("mule_notifier")
let assert Ok(instance) =
mule.start(MuleSpec(
engine: in_memory.new(storage.data),
notifier: isolated.new(process.named_subject(notifier_name)),
notifier_child: isolated.child(notifier_name),
registry: worker_registry.new() |> worker_registry.register(say_hello),
queues: [#("default", 10)],
stage_interval: duration.seconds(1),
plugins: [],
))
// Enqueue work; the queue's producer wakes and runs it.
let assert Ok(_job) = mule.insert(instance, say_hello, Nil)
Nil
}
For a database-backed setup (Postgres engine, caller-owned pool) and the cross-node notifier, see the Examples below.
Further documentation can be found at https://hexdocs.pm/mule.
Postgres storage
The Postgres engine ships versioned database migrations. To apply them, either
call migration.migrate/1 directly or generate migration files for an external
runner (cigogne / plain SQL):
gleam run -m mule/tasks/gen_migration -- priv/migrations
See docs/postgres-storage.md for the local Postgres setup (published on port 5433), both migration workflows, and how to run the engine tests.
Examples
The examples/ directory holds self-contained Gleam projects that
drive mule through its public API, grouped by what they show:
engines/— storage backends:in_memory(no database) andpostgres.plugins/— scheduled-work plugins:cron,pruner,lifeline, andreindexer.notifiers/— cross-node demos: two separate OS processes, and a job inserted on one node is run on the other. Inpostgresthe wake-up travels through PostgresLISTEN/NOTIFY; inpgthe processes are named Distributed Erlang nodes and it travels through apgprocess group, never touching the database.peers/— leader election: two processes elect exactly one leader and hand off when it leaves, through themule_peerslease (postgres) or a database-free:globallock (global).applications/— a full wisp + mist + lustre web app whose button enqueues a job.
Run most of them from their own directory with gleam run (the Postgres ones
need docker compose up -d first). The cross-node notifier demos run as two
processes against one database:
docker compose up -d
# terminal 1 — wait for it to print "ready":
cd examples/notifiers/pg && gleam run -m worker_node
# terminal 2:
cd examples/notifiers/pg && gleam run -m inserter_node
See examples/README.md for the full tour.
Development
gleam run # Run the project
gleam test # Run the tests