Repository navigation
feat!: run jobs and Phase 1 off the stream thread, per-bot switches - #91
Merged
Merged
Conversation
The bot ran on one thread, so Phase 2, Phase 3, the inbox pass, the cleanup and every Phase 1 duplicate search paused the r/all comment stream, and PRAW's stream only catches up on the newest 100 comments. Now the main thread only reads the stream. Each scheduled job runs on its own PeriodicJob thread (Phase 2 and Phase 3 share a lock), and Phase 1 runs on a pool of worker threads fed with comment IDs through a bounded queue. PRAW instances and database connections are per thread. SIGTERM and SIGINT stop every thread gracefully; Phase 2 and Phase 3 stop between entries. The schedule dependency is removed. Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Comments now say why the code is threaded instead of comparing it with the single-threaded loop it replaced. Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
The function sleeps and returns whether a shutdown was requested, so name it for the question its result answers. Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Each bot account can be turned off on its own with AUTO_CROSSPOST_BOT_ENABLED, SUB_DOESNT_EXIST_BOT_ENABLED, SAME_SUBREDDIT_BOT_ENABLED and SAME_POST_BOT_ENABLED (default True). A disabled bot never comments, posts or deletes, and its inbox is left unread. With all four off, only the stream, filtering, DB inserts, Phase 2 and the known-subreddits buffer run. BREAKING CHANGE: LISTEN_ONLY is removed. LISTEN_ONLY=True now stops the bot at startup with a message pointing to AUTO_CROSSPOST_BOT_ENABLED=False. Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
BREAKING CHANGE: python -m racb --only-phase2 no longer exists. Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
Co-Authored-By: Toldry <toldry@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Querent · project thread
Before: the bot ran on one thread. While Phase 2, Phase 3, the inbox pass, the cleanup or a Phase 1 duplicate search (up to 200 preview downloads) ran, nobody read the r/all stream. PRAW's stream only catches up on the newest 100 comments, so comments posted meanwhile were lost.
LISTEN_ONLY=Trueonly stopped crossposting; the three auxiliary bots still replied and the cleanup job still deleted posts.After: the main thread only reads the stream. Every scheduled job runs on its own thread, Phase 1 runs on a pool of worker threads (
PHASE1_WORKERS, default 4), anddocker stopshuts all of them down cleanly. Each bot account has its own on/off switch, which replacesLISTEN_ONLY.Breaking (hence
feat!):LISTEN_ONLYis removed and ignored. An.envwithLISTEN_ONLY=Truemust switch toAUTO_CROSSPOST_BOT_ENABLED=False, or the bot starts crossposting.--only-phase2flag is removed. It was added for an old HerokuProcfileentry, and nothing uses it now.How:
racb/workers.pyaddsPeriodicJob, one thread per job. A job's next run starts one interval after its previous run ends. Phase 2 and Phase 3 share a lock, so as before they never overlap.Phase1Workers. The stream thread runs only the regex and queues the comment ID of each match. The queue holds 1000 IDs; matches that don't fit are dropped and counted in the heartbeat. A worker then fetches the comment again through its own PRAW instance, which costs one extra request per match.reddit.get_reddit_instance()returns a separate PRAW instance per thread and account, because PRAW isn't thread safe.db.get_connection()gives each thread its own connection. The schema script runs on one connection at a time, because concurrentCREATE OR REPLACE FUNCTIONcan fail.racb/core/shutdown.pyholds a stop signal that SIGTERM and SIGINT set.shutdown.stop_requested_within(), and Phase 2 and Phase 3 stop between entries.start_bot()waits up to 50 s for the threads, and compose getsstop_grace_period: 60s.AUTO_CROSSPOST_BOT_ENABLED,SUB_DOESNT_EXIST_BOT_ENABLED,SAME_SUBREDDIT_BOT_ENABLEDandSAME_POST_BOT_ENABLED, allTrueby default.--process-oneauthenticates only AutoCrosspostBot, the one account it uses. It exits with code 2 if that bot is disabled.StreamMetricsand theknown_subredditsbuffer get locks, and log lines name their thread.scheduledependency is removed..env.exampleand the CHANGELOG are updated, and all 1725 unit tests pass.Rate limits: each thread's prawcore limiter paces itself on Reddit's shared per-account quota headers. Together they can overshoot by a few requests near the end of a window, which ends in a
TooManyRequestsback-off (documented in AGENTS.md section 7). I haven't tested this against live Reddit.Folds in #93.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Bi2vprJUUCtGDcGHxadEba