From e202ad3a9eb7db7a900f768509a45260deac7b45 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Fri, 15 May 2026 16:38:01 +0200 Subject: [PATCH] feat(06-02): add just worker target and document worker in README - justfile: worker target depends on db-up, passes MinIO dev defaults (DATABASE_URL, S3_ENDPOINT/BUCKET/REGION/ACCESS_KEY/SECRET_KEY/USE_PATH_STYLE) - README: replace skeleton section with full "Running the Worker" docs (just worker command, expected logs, single-worker constraint, graceful shutdown, failed job retry observation) --- backend/README.md | 58 +++++++++++++++++++++++++++++++++++++++++------ backend/justfile | 11 +++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/backend/README.md b/backend/README.md index 736acab..d016ecb 100644 --- a/backend/README.md +++ b/backend/README.md @@ -66,7 +66,7 @@ identical. If you don't have podman: backend/ cmd/ web/main.go # HTTP server entry point - worker/main.go # background worker (skeleton — boot/log/shutdown only) + worker/main.go # background worker — river periodic jobs (Phase 6) internal/ db/ # pgxpool wiring + sqlc-generated queries web/ # chi router, handlers, middleware, design-system @@ -123,17 +123,61 @@ Every command in this table is a recipe in `backend/justfile`. | `just build` | Generates assets, then builds `bin/web` and `bin/worker` | Producing release binaries locally | | `just clean` | Removes `bin/`, `tmp/`, `static/htmx.min.js`, `static/tailwind.css`, and `*_templ.go` files | Reset to a fresh-clone state without dropping the Postgres volume | -## Worker (skeleton — Phase 1 only) +## Running the Worker -`cmd/worker` in Phase 1 boots, logs `worker ready`, and idles waiting for a -signal. Real job runtime lands in Phase 6 (D-03). To run it manually: +`cmd/worker` is the background job processor. It runs river periodic jobs against +the same Postgres as `cmd/web`. Start it with: ``` -DATABASE_URL=postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable \ - go run ./cmd/worker +just worker ``` -Ctrl-C to exit. +This requires `just db-up` (handled automatically as a dependency) and MinIO +running (used by the orphan-file cleanup job). If MinIO is not running, the worker +will exit on startup with "file store init failed". + +### What to expect + +- Structured logs appear immediately at startup. +- A `"worker ready"` log line appears within a few seconds after `rivermigrate` + and S3 init complete. +- A `"worker heartbeat"` log line appears almost immediately (the heartbeat job + is configured with `RunOnStart: true`, so it fires on the first scheduler tick + which happens within seconds of startup). +- Subsequent heartbeat logs appear every ~1 minute. +- The orphan-file cleanup job runs every hour (no `RunOnStart` — first run is + ~1 hour after startup). + +### Single-worker constraint + +**Run only one worker process at a time (v1).** River uses advisory locks for +leader election and concurrent rivermigrate runs are unsafe. Do not run multiple +worker instances against the same database in this version. + +### Graceful shutdown + +Send SIGINT (Ctrl+C) and observe: + +``` +{"level":"INFO","msg":"shutting down"} +{"level":"INFO","msg":"shutdown complete"} +``` + +The worker calls `riverClient.StopAndCancel` with a 10-second timeout, which +cancels in-flight job contexts and waits for goroutines to exit before closing +the pool. + +### Observing failed job retries + +River logs each failure via the `SlogErrorHandler`. A failed job produces a log +line like: + +``` +{"level":"ERROR","msg":"job error","job_id":42,"job_kind":"heartbeat","attempt":1,"max_attempts":25,"err":"..."} +``` + +River retries up to 25 times with exponential backoff (`attempts^4` + jitter). +After 25 failed attempts the job is moved to the discarded state in `river_job`. ## Troubleshooting diff --git a/backend/justfile b/backend/justfile index c7ecc91..3575531 100644 --- a/backend/justfile +++ b/backend/justfile @@ -112,6 +112,17 @@ dev: db-up just generate DATABASE_URL='{{ database_url }}' SESSION_SECRET=191affeb1624de1f0e07bd5cfab14cd655510a24f7e673bd784ea56847890caf air -c .air.toml +# Start the worker binary (development — requires db-up and MinIO running). +worker: db-up + DATABASE_URL='{{ database_url }}' \ + S3_ENDPOINT='http://localhost:9000' \ + S3_BUCKET='xtablo' \ + S3_REGION='us-east-1' \ + S3_ACCESS_KEY='minioadmin' \ + S3_SECRET_KEY='minioadmin' \ + S3_USE_PATH_STYLE='true' \ + go run ./cmd/worker + test: just generate go test ./...