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)
This commit is contained in:
parent
6e70478417
commit
e202ad3a9e
2 changed files with 62 additions and 7 deletions
|
|
@ -66,7 +66,7 @@ identical. If you don't have podman:
|
||||||
backend/
|
backend/
|
||||||
cmd/
|
cmd/
|
||||||
web/main.go # HTTP server entry point
|
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/
|
internal/
|
||||||
db/ # pgxpool wiring + sqlc-generated queries
|
db/ # pgxpool wiring + sqlc-generated queries
|
||||||
web/ # chi router, handlers, middleware, design-system
|
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 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 |
|
| `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
|
`cmd/worker` is the background job processor. It runs river periodic jobs against
|
||||||
signal. Real job runtime lands in Phase 6 (D-03). To run it manually:
|
the same Postgres as `cmd/web`. Start it with:
|
||||||
|
|
||||||
```
|
```
|
||||||
DATABASE_URL=postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable \
|
just worker
|
||||||
go run ./cmd/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
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,17 @@ dev: db-up
|
||||||
just generate
|
just generate
|
||||||
DATABASE_URL='{{ database_url }}' SESSION_SECRET=191affeb1624de1f0e07bd5cfab14cd655510a24f7e673bd784ea56847890caf air -c .air.toml
|
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:
|
test:
|
||||||
just generate
|
just generate
|
||||||
go test ./...
|
go test ./...
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue