Skip to content

feat: scale core — process split, send outbox, sticky incoming - #12

Merged
kinton merged 2 commits into
mainfrom
fix/outbox-heartbeat-and-supervisor
Sep 3, 2026
Merged

feat: scale core — process split, send outbox, sticky incoming#12
kinton merged 2 commits into
mainfrom
fix/outbox-heartbeat-and-supervisor

Conversation

@kinton

@kinton kinton commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • python main.py is still the only start/deploy command, but it now supervises bot / updater / jobs as child processes. A crashed RSS circle no longer restarts Telegram receive (supervisorctl restart yourcast unchanged; stopasgroup so the whole tree dies on restart).
  • User-triggered rec / update jobs are persisted in a SQLite outbox (pending → leased → done/failed) with lease heartbeat, so a process restart does not drop episode sends. Claim uses BEGIN IMMEDIATE.
  • Incoming handlers stick to one worker per chat. Shared updater cursor / resend flags / message-id cache move to WAL bot_runtime_kv so gdbm is not the cross-process source of truth. Telethon file session stays bot-only; send workers use StringSession.

This composes the useful parts of PR #7 (supervisor) and PR #11 (outbox), plus the blockers those PRs left: import-time send workers in every process, gdbm cursor races, and round-robin incoming races on FSM.

What this is not

  • Not a fourth sender process yet. Automatic circle still sends inline in the updater (proven path). User sends go through the outbox in the bot process.
  • Not PR Receive updates via Bot API when Telethon MTProto is blocked #5 (Bot API receive fallback). That is availability on filtered networks, not scale, and conflicts with this main.py.

Test plan

  • python db/test_send_outbox.py — enqueue/claim/lease/heartbeat/restart/exclusive claim
  • python db/test_runtime_kv.py — kv, migrate from shelve, updater cannot open file Telethon session
  • python app/core/test_process_supervisor.py — crashed role restarts, sibling pid unchanged
  • python app/core/balancers/test_sticky.py — sticky + least-loaded
  • existing db/test_connection.py, db/test_channel_poll.py, db/test_count_users.py, app/jobs/test_nosub_digest.py, app/service/podcast/test_feed_etag.py
  • Staging: python main.py starts three children, /start still works, manual episode send survives kill of bot child, updater crash does not drop receive
  • Production deploy only after that staging check (this PR does not merge itself)

Keep python main.py as the only start command, but run receive, the
RSS circle, and background jobs as child processes so a dead updater
no longer restarts Telegram receive. User-triggered rec/update work
survives a restart via a leased sqlite outbox, incoming handlers stick
to one worker per chat, and shared updater cursor state moves out of
gdbm into WAL sqlite.
Patreon writes FSM state, so that watcher stays with receive. flock
does not make gdbm safe to share with updater or jobs.
@kinton
kinton merged commit 12872a3 into main Sep 3, 2026
@kinton
kinton deleted the fix/outbox-heartbeat-and-supervisor branch September 3, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant