Documentation
Worker & Queue
How the git-sync worker processes jobs: per-slug dedup, the stale-lock runner, retry backoff, max-attempt dead-lettering, and structured logs.
Worker & Queue
Briter never pushes to git from a web request. The web app writes a job file to a disk-backed queue; a separate worker process drains that queue, stages the declared paths, commits, and pushes. The two processes share the storage/ directory (a Docker volume in production) so the queue is visible from both sides. See Architecture for the wider picture and Docker for running the worker as a service.
The queue
The queue is DiskJobQueue (lib/queue/disk-job-queue.ts): one JSON file per job under storage/queue/ (BRITER_QUEUE_ROOT). Each git-sync job records the post slug, the paths to stage, the commit message, a scheduledFor instant, the attempt count, and a status.
Per-slug dedup
A post has at most one pending job. When you re-save a post, enqueue() removes any existing non-terminal job for the same slug before writing the new one. This means editing a scheduled post never leaves a stale job behind that still fires the old version.
Scheduling hold
listDue() only returns jobs whose scheduledFor is at or before now. A post scheduled for the future is held in the queue — nothing reaches git or git history before its publish instant. Drafts and immediate publishes get a scheduledFor of enqueue time, so they sync right away. This is the mechanism behind Scheduling & archiving.
The worker process
Run the worker with:
bun run worker # poll-and-loop (production)
bun run worker:once # drain once and exit (cron-style)
The entrypoint is scripts/run-git-sync-worker.mjs; the processing logic is GitSyncWorker.processDueJobs() (lib/worker/git-sync-worker.ts).
Single-flight lock with stale recovery
Only one worker may run at a time. On start, the entrypoint acquires storage/worker.lock, a file containing the holder's PID. If another live worker holds the lock, the new process logs "another worker instance is active, skipping" and exits cleanly.
A crashed worker would otherwise leave the lock behind and wedge every future sync, so the lock is reclaimable (lib/worker/lock-file.ts) when:
- the recorded PID is not alive (checked with
process.kill(pid, 0)), or - the lock file is older than the staleness TTL (
BRITER_WORKER_LOCK_STALE_MS, default 60000 ms) — this covers PID reuse, where a dead worker's PID has been recycled by an unrelated process, or - the lock file is unreadable or contains garbage.
Per-job processing
For each due job, the worker:
- Validates the job's paths against the active adapter's allowlist (
validatePaths). A job with no allowed paths is marked failed (nopaths). See Adapters for the allowlists. - Asserts it is on the configured branch (
BRITER_GIT_BRANCH), then stages the allowed paths. - If staging produced no changes, the job is removed (
nochange) — re-saving identical content is a no-op, not a failure. - Otherwise commits with the job's message and pushes to
BRITER_GIT_REMOTE/BRITER_GIT_BRANCH, then removes the job (published).
When
BRITER_WORKER_DRY_RUNis true (the default), every step runs except the real push — useful for verifying wiring before going live. Set it tofalseto publish for real. See Configuration Reference.
Retry backoff and dead-lettering
If processing throws, the job is rescheduled with exponential backoff: 1 min → 5 min → 30 min (the last delay repeats for further attempts). The attempt counter increments each time.
Once attempts reach BRITER_WORKER_MAX_ATTEMPTS (default 8), the job is dead-lettered: its status becomes failed, it stops being retried, and it no longer blocks a fresh pending job for the same slug. Dead-lettered jobs surface in the dashboard's Failed sync view with their lastError; re-saving the post enqueues a fresh attempt.
Structured logs
Each job emits structured single-line JSON logs (lib/worker/git-sync-worker.ts) prefixed [briter-worker], with a start entry and then an outcome:
| Outcome | Meaning |
|---|---|
published |
Committed and pushed successfully. |
nochange |
Staging produced no diff; job dropped. |
nopaths |
No allowed paths in the job; marked failed. |
failed |
Attempt failed; will retry with backoff. |
dead-lettered |
Reached max attempts; will not retry. |
Each entry carries jobId, slug, and attempt (1-based for the current run) so failures are traceable per post.
Tuning
| Variable | Default | Effect |
|---|---|---|
BRITER_WORKER_DRY_RUN |
true |
false enables real pushes. |
BRITER_WORKER_POLL_INTERVAL_MS |
5000 |
Queue poll interval. |
BRITER_WORKER_MAX_ATTEMPTS |
8 |
Attempts before dead-lettering. |
BRITER_WORKER_LOCK_STALE_MS |
60000 |
Stale-lock reclaim age. |
Full descriptions and defaults are in the Configuration Reference.