8000 GitHub - cargopete/wren: An ergonomic RabbitMQ / AMQP messaging library for Gleam · GitHub
[go: up one dir, main page]

Skip to content
cargopetePublic

About

An ergonomic RabbitMQ / AMQP messaging library for Gleam

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

wren

An ergonomic RabbitMQ / AMQP messaging library for Gleam, built on the BEAM and OTP.

Small, quick, and busy — a wren is a tiny bird that does a great deal. This library aims to do the same for your messages: a friendly, type-safe layer over AMQP that lets OTP handle the hard parts (supervision, reconnection, fault tolerance) so you don't have to.

Status

Stable — 1.0. The public API is settled and the whole feature set is exercised by an integration suite against a real broker (green in CI, which stands up its own RabbitMQ):

  • ✅ Typed connections & channels over the Erlang amqp_client
  • ✅ A supervised, actor-based consumer (OTP restarts and re-subscribes on crash)
  • ✅ Producer options — exchange, routing key, headers, priority, expiration, mandatory
  • ✅ A Codec abstraction with a JSON codec, plus typed publish_encoded / decode_message
  • ✅ Router-style consumer — dispatch by message kind to typed handlers, with a fallback
  • ✅ Topology management — exchanges, bindings, deletes, and x-* queue/exchange arguments
  • ✅ Retry policy & metadata — backoff strategies, header round-tripping (wren/retry)
  • ✅ Retry/dead-letter infrastructure — delay queues with TTL, dead-letter exchange, DLQ
  • ✅ Connection recovery — self-healing consumer that reconnects with backoff, plus QoS prefetch
  • ✅ Client config & ergonomics — config_from_env, vhost/heartbeat/timeout, a Client front door

And, since v0.2:

  • ✅ Publisher confirms (publish_confirmed) + persistent delivery (with_persistence)
  • ✅ Concurrent delivery processing, bounded by prefetch (start_consumer_concurrent)
  • ✅ Connection pool (start_pool) with round-robin channel handout and pool_stats
  • ✅ Active health_check, kind-based producer (publish_for_kind), TLS, and topology guards
  • ✅ Consumer subscribe options — auto-ack, exclusive, no-local, consumer tag, subscription arguments
  • ✅ Full AMQP message properties (correlation_id/reply_to for RPC, …) and batch / multi-target publishing
  • ✅ Raw byte (BitArray) payloads, with publish_text / message_text for the text case

See ROADMAP.md for how each piece maps to a production AMQP client, and CHANGELOG.md for what landed when.

Design

  • A typed, router-style API for consuming messages by kind.
  • Producers with sensible defaults and explicit routing.
  • Retry and dead-letter handling driven by message headers and broker topology.
  • Connection recovery that leans on OTP supervision rather than hand-rolled loops.

A quick taste

Publish a typed message with a kind, then consume and decode it:

import wren
import wren/codec

// A codec is just an encoder + decoder; `codec.json` builds one from gleam_json.
let order_codec = codec.json(encode_order, order_decoder)

// Publish, tagging the message with its kind for routing.
let options =
  wren.publish_options()
  |> wren.route("orders")
  |> wren.with_kind("order.created")
let assert Ok(_) = wren.publish_encoded(channel, order, order_codec, options)

// Consume under supervision, routing by kind to typed handlers.
let router =
  wren.router()
  |> wren.handle("order.created", order_codec, fn(order: Order) {
    handle(order)
    wren.Ack
  })
  |> wren.fallback(fn(_message) { wren.Reject })

let assert Ok(_) = wren.start_router(channel, "orders", router)

Handlers receive the already-decoded value; a malformed payload is rejected and logged before it ever reaches your code. Need the headers or routing key too? Reach for handle_with, which also hands you the raw Message.

Retries & dead-lettering

Give the consumer a retry policy and wren builds the delay-queue + dead-letter topology for you. A handler returning wren.Retry redelivers the message after a backoff (via a TTL'd delay queue); once attempts are exhausted — or on wren.DeadLetter — it goes to the dead-letter queue.

import wren/retry

let infra =
  wren.retry_infrastructure(
    "orders",
    retry.RetryPolicy(
      strategy: retry.ExponentialBackoff(
        initial_ms: 1000,
        max_ms: 60_000,
        multiplier: 2.0,
      ),
      max_attempts: 5,
    ),
  )

// Declares the topology and starts consuming, routing by kind.
let assert Ok(_) = wren.start_router_with_retry(channel, router, infra)

Examples

Runnable, self-contained programs live under src/wren/examples:

gleam run -m wren/examples/router     # dispatch typed messages by kind
gleam run -m wren/examples/retry      # fail once, then succeed via a delay queue
gleam run -m wren/examples/recovery   # a self-healing consumer
gleam run -m wren/demo                # the original supervised-consumer demo

Development

Everything talks to a real broker. Bring one up first:

docker compose up -d            # start a local RabbitMQ (wren / wren)
gleam test                      # run the integration + unit suites
gleam run -m wren/examples/router
docker compose down             # stop the broker

Licence

Released under the MIT licence.

About

An ergonomic RabbitMQ / AMQP messaging library for Gleam

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0