News post → town crier + Discord announcement pipeline #52
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/news-announce-pipeline"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Replaces the old fire-and-forget, Discord-only announce-on-publish with a retry-safe, two-leg announcement pipeline. When a post transitions into published news (a
false→truepublish while in news, or a category change into news while already published), the site enqueues anannounce_jobsrow with two independent delivery legs:POST /towncrierviauoLinkClient, stable idpost-<id>so a retry replaces rather than duplicates the in-game entry.POST /internal/announceviabotInternalClient(the bot remains the single source of truth for the#newschannel).A light in-process poller (
utils/announceWorker) sweeps the table everyANNOUNCE_POLL_MSand dispatches each due leg with its own exponential backoff (30s → 2h, 6 attempts). Transient failures (503/504/network) retry; data/config failures fail fast (400 over-cap, 401/409). Publishing never blocks on the sidecar or Discord — enqueue is local DB only. The parentstatusis adone/partial/failedrollup of the two legs;posts.announced_atis stamped once both deliver.Admin visibility
GET /admin/posts/:id/announce+ a per-leg Retry button, surfaced in the PostEditor for news posts (useful after fixing the sidecar/news-channel without re-publishing). The old manual/admin/uo-link/towncrierform is untouched.Data model
announce_jobstable (two-leg state machine, idempotent-migration friendly).posts.announced_at+posts.announce_job_id(added via the existing idempotentALTER … IF NOT EXISTSboot migration).Testing
announceJobs.logicand are unit-tested —server/test/announceJobs.test.js(10 tests). Full server suite: 152/152 green.Config
New env (documented in
server/.env.example+ README):ANNOUNCE_POLL_MS(default 15000),TOWNCRIER_DURATION_SEC(default 3600, ≤ 86400).🤖 Generated with Claude Code
https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ
Replace the fire-and-forget Discord-only announce on publish with a retry-safe, two-leg pipeline. When a post transitions into published-news (false→true publish while in news, or category→news while published), an announce_jobs row is enqueued with two INDEPENDENT delivery legs: • town crier — sidecar POST /towncrier via uoLinkClient (stable id `post-<id>` so a retry replaces rather than duplicates) • discord — bot POST /internal/announce via botInternalClient (single source of truth for the #news channel stays in the bot) An in-process poller (utils/announceWorker) sweeps the table every ANNOUNCE_POLL_MS and dispatches each due leg with its own exponential backoff (30s→2h, 6 attempts). A leg is retried on transient failures (503/504/network) and failed fast on data/config errors (400 over-cap, 401/409). Publishing never blocks on the sidecar or Discord — enqueue is local DB only. Parent `status` is a done/partial/failed rollup of the two legs; posts.announced_at is stamped once both deliver. Admin visibility: GET /admin/posts/:id/announce + a per-leg Retry (POST .../announce/retry) surfaced in the PostEditor for news posts. Pure decisions (text build/caps, classification, backoff, rollup) live in announceJobs.logic and are unit-tested (server/test/announceJobs.test.js, 10 tests). The old manual /admin/uo-link/towncrier form is untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0114TpmrNW4wNXsHq5CR72jQ