Phase 2b — durable Postgres queue + worker (gated on DATABASE_URL)
Some checks failed
Docker Build / build-and-push-image (push) Has been cancelled

Adds the async dispatch infrastructure :

- Postgres pool + embedded migration (CREATE TABLE/INDEX IF NOT EXISTS
  gateway_jobs). Auto-applied at boot. lib/pq driver (matches webapp
  convention).
- queue.go : Enqueue (idempotent on UNIQUE(bot_slug, update_id) — handles
  Telegram redelivery), Pop with FOR UPDATE SKIP LOCKED, MarkDone,
  MarkFailed with exponential backoff (30s → 2m → 10m → 1h → dead at 5).
- worker.go : goroutine that drains the queue, dispatches via the same
  Handler interface as sync, schedules retries on failure, notifies the
  user once when a job goes to dead.
- BotConfig gains `async: bool`. Registry refuses bots with async=true
  if DATABASE_URL is unset (queue=nil).
- Server : when bot.Async, the webhook ack is immediate ; the update
  payload is enqueued for the worker.

When DATABASE_URL is unset (current default), queue/worker stay disabled
and only sync handlers (echo, http, auth) work — no breaking change to
the running cluster.

Refs ~/.claude/plans/pour-les-notifications-on-inherited-seal.md § Phase 2.
This commit is contained in:
2026-05-09 14:38:41 +02:00
parent f90d5efdae
commit 799e10dcc2
11 changed files with 445 additions and 21 deletions

View File

@@ -20,6 +20,13 @@ type BotConfig struct {
// `requireAuth: false` is required to expose a bot publicly.
// Forced to false for handler=auth (chicken-and-egg).
RequireAuth *bool `yaml:"requireAuth,omitempty"`
// Async, when true, dispatches incoming Updates through the durable
// Postgres queue + worker (Phase 2b) instead of running inline. The
// webhook ack returns 200 immediately ; the worker may retry the job
// with backoff if the handler fails. Required for handlers that may
// outlive the Telegram webhook timeout (shell, script, ollama).
// Requires DATABASE_URL to be set, otherwise registry refuses to start.
Async bool `yaml:"async,omitempty"`
// HTTP is the per-bot config for the `http` handler. Required when
// handler=http. See handler_http.go.
HTTP *HTTPConfig `yaml:"http,omitempty"`