Skip to content

feat: read every new comment by ID range, resume after restarts - #98

Merged
Toldry merged 4 commits into
masterfrom
claude/project-thread-bf84xq
Oct 16, 2026
Merged

Toldry merged 4 commits into
masterfrom
claude/project-thread-bf84xq

Conversation

@Toldry

@Toldry Toldry commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Requested by Querent · project thread

Before: the bot read r/all through PRAW's comment listing stream, 100 comments per request and one request at a time, about 7 s each by day. On 2026-10-15/16 it saw about 850 comments a minute by day and up to 2,500 at night, when Reddit answered faster, so it missed most of r/all. Every restart (one per push to master) and every stream error skipped whatever was posted in between.

After: the bot reads every new comment by ID. Reddit numbers comments in base 36, in order across the whole site. The main thread polls the newest r/all comment ID every 10 s and queues the blocks of 100 IDs up to it. STREAM_READERS threads (default 4, taking turns between the 4 accounts) each fetch a block with one /api/info request and pass on the comments r/all would show (not NSFW, quarantined, private or on a user profile). Requests per minute follow Reddit's comment rate, about one per 100 new comments.

The reader saves its position (stream_cursors) every 30 s and at shutdown, so a restart resumes where it stopped, up to 200,000 IDs back. STREAM_SOURCE=listing brings back the old stream, which now resumes after the newest comment seen when it hits an error.

The heartbeat also says how comments were read, for example reads: 412 requests, 87.3 comments/request, 0.95 s/request | head: 50 polls, 1.70 s/poll | behind: 9 s, 340 IDs.

How:

  • New comment_reader.py (CommentReader), and main.run_stream picks the source.
  • StreamMetrics gains the reading figures.
  • New stream_cursors table with save_stream_cursor / get_stream_cursor. I ran the schema script twice against PostgreSQL 16 to check it is idempotent.
  • Phase1Workers.submit is now locked, because several readers call it.
  • New scripts/verify_comment_ids.py, a read-only live check of the reader's assumptions to run on the VM before merging.

Not verified here, because this environment can't reach Reddit:

  • That comment IDs really are sequential site-wide.
  • That comments from /api/info carry over_18, quarantine and subreddit_type.

scripts/verify_comment_ids.py checks both. So does the new live test test_live_comment_reader_reads_recent_comments_by_id, which runs in the post-merge integration-tests job and blocks the deploy if the assumption is wrong.

Known trade-offs, added to AGENTS.md section 9:

  • Subreddits that opted out of r/all can't be identified from a comment, so their comments are now read too.
  • After a crash (not a normal stop), up to 30 s of comments may be read twice.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FYGhPFNh3ZvVEr2YXt8Qmr

The r/all comment listing returns at most 100 comments per request, one
request at a time, so the bot saw about 850 comments a minute by day and
missed most of r/all. Comment IDs are numbered in order site-wide, so the
bot now fetches blocks of 100 consecutive IDs with /api/info on
STREAM_READERS threads spread over the 4 accounts, keeping only what r/all
would show. STREAM_SOURCE=listing keeps the old stream as a fallback.

The reader saves its position (stream_cursors) every 30 s and at shutdown,
so restarts and redeploys resume instead of skipping comments. The listing
stream now resumes after the newest comment seen after an error.

The heartbeat also reports requests, comments per request, seconds per
request, how far behind the newest comment the bot is, and CPU use
(process share of a core and VM steal time).

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_01FYGhPFNh3ZvVEr2YXt8Qmr
@Toldry Toldry self-assigned this Oct 16, 2026
@Toldry
Toldry marked this pull request as ready for review October 16, 2026 20:03
claude and others added 3 commits October 16, 2026 20:16
…CPU figures

GCP's Always Free tier limits instance hours, disk and egress, not CPU, so
the heartbeat's CPU and steal figures are removed. scripts/verify_comment_ids.py
checks against live Reddit that comment IDs follow creation time, that ID
blocks come back mostly full with the fields the r/all filter reads, how
fast IDs are handed out, and what each request costs.

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_01FYGhPFNh3ZvVEr2YXt8Qmr
The live check showed /api/info comments carry no over_18 or quarantine
field, so the reader's NSFW filter did nothing. Phase 1 now drops
matches on NSFW or quarantined posts, reading the submission it already
fetches. The r/all listing sometimes returns nothing for limit=1, which
would have stopped the head poll; it now asks for 25 and takes the
newest.

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_01FYGhPFNh3ZvVEr2YXt8Qmr
@Toldry
Toldry merged commit 372f663 into master Oct 16, 2026
4 checks passed
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.

2 participants