Packages

Durable background jobs for Gleam: an Oban port with Postgres, SQLite and in-memory engines, queues, cron, plugins and typed telemetry.

Current section

Files

Jump to
mule README.md
Raw

README.md

# mule
[![Package Version](https://img.shields.io/hexpm/v/mule)](https://hex.pm/packages/mule)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/mule/)
```sh
gleam add mule
```
```gleam
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](#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):
```sh
gleam run -m mule/tasks/gen_migration -- priv/migrations
```
See [docs/postgres-storage.md](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/`](examples/) directory holds self-contained Gleam projects that
drive `mule` through its public API, grouped by what they show:
- **[`engines/`](examples/engines/)** — storage backends: `in_memory` (no
database) and `postgres`.
- **[`plugins/`](examples/plugins/)** — scheduled-work plugins: `cron`,
`pruner`, `lifeline`, and `reindexer`.
- **[`notifiers/`](examples/notifiers/)****cross-node** demos: two separate
OS processes, and a job inserted on one node is run on the other. In
`postgres` the wake-up travels through Postgres `LISTEN`/`NOTIFY`; in `pg`
the processes are named Distributed Erlang nodes and it travels through a
`pg` process group, never touching the database.
- **[`peers/`](examples/peers/)** — leader election: two processes elect
exactly one leader and hand off when it leaves, through the `mule_peers`
lease (`postgres`) or a database-free `:global` lock (`global`).
- **[`applications/`](examples/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:
```sh
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](examples/README.md) for the full tour.
## Development
```sh
gleam run # Run the project
gleam test # Run the tests
```