Files
mc-router/docs/AUTOMC.md
T
claude-timemachine 657fca325e automc: pg LISTEN/NOTIFY route source + HTTP waker
Adds opt-in extension package internal/automc/ that:
- Subscribes to Postgres notifications on a 'servers' table and pushes
  route changes into server.Routes (no file I/O, no fsnotify).
- Provides a WakerFunc that POSTs to a configurable HTTP control plane
  (server-manager) and polls until state=running.

When AUTOMC_DSN is unset, Wire() is a no-op and the binary behaves
exactly like upstream itzg/mc-router. Single patch site in main.go
(import + 4-line call) keeps upstream rebases trivial.

See docs/AUTOMC.md for env vars and the expected DB schema/trigger.
2026-05-27 11:10:02 +02:00

3.5 KiB

automc extensions

Soft fork of itzg/mc-router that adds Postgres-driven route management and an HTTP waker, without touching upstream behavior by default.

The internal/automc package is opt-in via env vars: with AUTOMC_DSN unset, the binary behaves exactly like upstream.

Environment variables

Var Required Purpose
AUTOMC_DSN yes (to enable) Postgres DSN, e.g. postgres://user:pass@host:5432/automc?sslmode=disable. When unset, automc is a no-op.
AUTOMC_WAKER_URL no Base URL of the waker control plane (server-manager). When set, stopped backends are auto-started on login.
AUTOMC_WAKER_TOKEN no Sent as X-API-Key header on every waker request.

Recommended companion upstream flags:

  • --use-asleep-motd / --use-loading-motd — supplies friendly MOTD to clients during the wake window. Already implemented upstream; automc does not duplicate this.

Postgres schema

Apply this once to the database referenced by AUTOMC_DSN. mc-router only reads; the trigger is what tells it to re-read.

CREATE TABLE IF NOT EXISTS servers (
    name    TEXT PRIMARY KEY,
    domain  TEXT NOT NULL,
    address TEXT NOT NULL,
    state   TEXT NOT NULL DEFAULT 'stopped',
    UNIQUE(domain)
);

CREATE OR REPLACE FUNCTION automc_notify_routes_changed() RETURNS trigger AS $$
BEGIN
    PERFORM pg_notify('automc_routes_changed', '');
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS automc_servers_route_notify ON servers;
CREATE TRIGGER automc_servers_route_notify
    AFTER INSERT OR UPDATE OF domain, address, state OR DELETE ON servers
    FOR EACH ROW EXECUTE FUNCTION automc_notify_routes_changed();

The trigger fires on every mutation to a route-relevant column. mc-router holds a persistent LISTEN automc_routes_changed and re-runs SELECT name, domain, address FROM servers WHERE domain != '' AND address != '', diffing against its in-memory map. Adds/removes/changes call server.Routes.CreateMapping and DeleteMapping directly — no file I/O.

State column is not read by mc-router; it exists to drive the trigger and for the waker's own ready-check.

Waker contract

When AUTOMC_WAKER_URL is set, every route is registered with a WakerFunc that the upstream connector calls only when a client tries to LOGIN (not on status pings — those are answered locally via --use-asleep-motd).

The waker:

  1. POST {AUTOMC_WAKER_URL}/servers/{name}/start — fire-and-forget start signal. 409 Conflict is treated as success (already starting).
  2. Polls GET {AUTOMC_WAKER_URL}/servers/{name} every 2 s, expecting JSON {"state":"running","address":"host:port"}.
  3. Returns the polled address once state == "running", or errors after 90 s.

The polled address overrides the route's static address for that connection only — useful when the backend's IP is allocated lazily.

Upstream sync

make sync-upstream

Fetches upstream/main, rebases the automc branch onto it, builds, and runs the automc tests. The patch surface is intentionally tiny so rebase conflicts are rare:

cmd/mc-router/main.go  — 1 import line + 4-line Wire call
internal/automc/       — new directory; no upstream conflicts possible
docs/AUTOMC.md         — new doc; no upstream conflicts
Makefile               — appended targets only
go.mod / go.sum        — pgx dep added; mergeable

If upstream renames server.Routes.CreateMapping or changes its signature, only pgsync.go:apply needs adjustment.

Verification

go build ./...
go test ./internal/automc/...
go vet ./...