Recology

Install

Release archives contain a single static binary. There is no runtime dependency beyond libc, and the musl build has none at all.

$ curl -fsSLO https://cdn.reco1ogy.com/releases/recology_1.10.0_linux_amd64.tar.gz
$ tar xzf recology_1.10.0_linux_amd64.tar.gz
$ sudo install -m 0755 recology /usr/local/bin/recology
$ recology version
recology 1.10.0 (linux/amd64)

Verify the archive against the checksum file published with each release before installing on anything you care about.

Prepare the store

Recology keeps routes, leases, and dead-letter entries in Postgres 13 or newer. Create a database and a role, then let the binary apply its own schema.

$ createdb recology
$ recology migrate --store postgres://recology@db.internal:5432/recology
applied 7 migrations, schema version 7

Migrations are forward-only and take an advisory lock, so running the command from two hosts at once is safe. The second invocation waits and then reports that there is nothing to apply.

Configuration

Configuration is a single YAML file, by default /etc/recology/recology.yaml. It validates on load. Unknown keys are an error rather than a warning, which catches typos in route names before they reach production.

store: postgres://recology@db.internal:5432/recology
listen: 127.0.0.1:9713

defaults:
  lease: 30s
  attempts: 5
  backoff: exponential
  jitter: true

routes:
  - name: reports
    workers: 4
    retry_budget: 5/min
    target: http://reports.internal:8080/run

  - name: webhooks
    workers: 16
    retry_budget: 30/min
    dead_letter:
      enabled: true
      retain: 14d
    target: http://dispatch.internal:8080/send

Credentials are read from the environment first. If RECOLOGY_STORE_URL is set it takes precedence over the store key, so you can keep the file free of secrets and commit it.

Your first route

A route can be created from the configuration file or directly from the command line. The command line version is useful for experimenting; commit the file version once you are happy with it.

$ recology route add reports --workers 4 --lease 30s \
    --target http://reports.internal:8080/run
created route "reports"

$ recology submit reports --payload '{"month":"current"}'
queued reports/1a04f (trace 1a04f8c31e77)

Running workers

A worker process claims leases for one or more routes. Concurrency is set per route in configuration, not per worker, so adding a worker host does not change the total amount of work in flight.

$ recology worker --routes reports,webhooks
ready claiming for 2 routes, max in flight 20

Workers exit cleanly on SIGTERM. On shutdown a worker stops claiming new leases, finishes what it holds, and releases anything still outstanding. Allow a grace period at least as long as your longest lease.

systemd unit

[Unit]
Description=Recology worker
After=network-online.target

[Service]
Type=simple
User=recology
Environment=RECOLOGY_STORE_URL=postgres://recology@db.internal:5432/recology
ExecStart=/usr/local/bin/recology worker --routes reports,webhooks
Restart=on-failure
RestartSec=5
TimeoutStopSec=90
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Metrics

The listener exposes /metrics in Prometheus text format and /healthz for liveness checks. Bind it to localhost and scrape through your existing agent, or bind it to an internal interface if you scrape centrally.

$ curl -s localhost:9713/metrics | grep lag
recology_route_lag_seconds{route="reports"} 1.4
recology_route_lag_seconds{route="webhooks"} 8.9

Lag is the metric worth alerting on. Pending depth alone is noisy, because a large batch submitted on purpose looks identical to a stalled route until you look at how old the oldest job is.

Upgrades

Replace the binary and restart. Workers on the previous version keep working against the same schema within a minor series, so a rolling restart needs no coordination. Across a minor version bump, run recology migrate first and check the changelog for migration notes.

Command reference

CommandDescription
recology migrateApply pending schema migrations.
recology route add|rm|listManage routes.
recology submit <route>Queue a single job.
recology workerRun a worker process.
recology statusPer-route pending, leased, failed, and lag.
recology tail <route>Stream state transitions.
recology lease inspect <id>Show one job's lease detail.
recology dlq list|replay|purgeWork with dead-letter entries.
recology config checkValidate a configuration file and exit.

Duration syntax

Durations accept an integer and a unit suffix: s, m, h, or d. Compound values such as 1h30m are accepted. Rates use the form count/unit, for example 30/min. A bare integer is rejected rather than assumed to be seconds.