fix(pipeline): repair Agerpres feed, archive lock starvation, enrichment cadence - #40
Conversation
…ent cadence Prod Convex audit surfaced three live issues (claim divergence & Apple auth left intentionally off): - Agerpres feed was permanently quarantined: www.agerpres.ro/rss/stiri 301-redirects to a dead allorigins.win proxy (520/522). Point the feed at the underlying bazqux createfeed extractor directly, which serves valid RSS. Safe: sources row is keyed by domain (unchanged); quarantine state is keyed by feedUrl (new URL starts fresh). - archiveStaleSingletonEvents skipped 100% of runs. Its hourly cadence is an exact multiple of the 20-min merge and 30-min recluster jobs, and Convex interval crons are epoch-phase-aligned, so it fired in lockstep with them every time and always hit a blocking lock. Move to a 53-min drifting cadence (coprime with 20/30/40/60) so it lands in quiet windows without starving the core clustering pipeline. Also stop counting deliberate "skipped" yields as failures in the job_error_rate SLO (archive_run_absent still catches a truly stuck job). - Enrichment cadence 40m -> 30m to work down the unprocessed-article backlog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WalkthroughCron schedules for enrich-articles and archive-stale-singleton-events were adjusted with updated comments. The Agerpres RSS feed URL was replaced with a Bazqux extractor proxy URL. checkPipelineAlerts now skips runs with status "skipped" when calculating per-job success ratios. ChangesBackend maintenance tweaks
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Poem A rabbit tweaks the clockwork gears, 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/backend/convex/pipeline.ts (1)
953-966: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy liftAlerting gap for jobs that only emit
skipped.Excluding
skippedlogs frombyJobmeans a job that keeps short-circuiting never entersjob_error_rate:<jobName>, so it can fail silently. OnlyarchiveStaleSingletonEventshas a separate absence alert here; other jobs don’t appear to have one.Either keep
skippedin the denominator for jobs without a dedicated absence check, or add a generic no-okalert per job.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/backend/convex/pipeline.ts` around lines 953 - 966, The per-job error-rate aggregation in pipeline.ts is dropping all skipped runs, which lets jobs that only short-circuit disappear from job_error_rate alerts. Update the byJob accumulation around the logs loop so skipped entries are either counted in the denominator for jobs that don’t have a dedicated absence check, or add a generic no-ok alert path for every job. Keep the existing special handling for archiveStaleSingletonEvents and ensure the logic around byJob, log.status, and the job_error_rate:<jobName> metric still reflects skipped-only behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/backend/convex/pipeline.ts`:
- Around line 953-966: The per-job error-rate aggregation in pipeline.ts is
dropping all skipped runs, which lets jobs that only short-circuit disappear
from job_error_rate alerts. Update the byJob accumulation around the logs loop
so skipped entries are either counted in the denominator for jobs that don’t
have a dedicated absence check, or add a generic no-ok alert path for every job.
Keep the existing special handling for archiveStaleSingletonEvents and ensure
the logic around byJob, log.status, and the job_error_rate:<jobName> metric
still reflects skipped-only behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 711cc59d-e21f-4984-9971-4712ff077bbe
📒 Files selected for processing (3)
packages/backend/convex/crons.tspackages/backend/convex/feeds.tspackages/backend/convex/pipeline.ts
Context
Production Convex audit found three live pipeline issues. Claim divergence and Apple auth were confirmed intentionally off and are left untouched.
Changes
1. Agerpres feed permanently quarantined → fixed
www.agerpres.ro/rss/stiriserver-side 301-redirects to anallorigins.winproxy wrapping abazquxscraper, and thealloriginslayer returns 520/522 (dead) — keeping the feed quarantined and every ingest rundegraded. Agerpres has no native RSS. Pointed the feed straight at the underlying bazqux createfeed extractor, which returns valid RSS (verified: 21 real articles dated today).sourcesrow is keyed by domain (agerpres.ro, unchanged); quarantine state is keyed byfeedUrl, so the new URL starts un-quarantined.2.
archiveStaleSingletonEventsskipped 100% of runs → fixedRoot cause is cadence arithmetic, not bad luck: Convex interval crons are epoch-phase-aligned, and the job's hourly cadence is an exact multiple of the 20-min merge (
60=3×20) and 30-min recluster (60=2×30) jobs — so it fired simultaneously with them every time and always hit a blocking pipeline lock (verified in run logs).crons.ts:{ hours: 1 }→{ minutes: 53 }(coprime with 20/30/40/60) so archive drifts into quiet windows. The core clustering pipeline keeps priority — not lease priority, which would starve it and not remove the concurrent-mutation hazard the lock guards.pipeline.ts:skippedruns no longer count as failures in thejob_error_rateSLO (a yield is a no-op). Thearchive_run_absentcheck still catches a genuinely stuck job.3. Enrichment cadence 40m → 30m
Works down the unprocessed-article backlog faster.
Testing
tsc --noEmitcleanfeeds.test.ts+feeds.smoke.test.tspass (14 passed, 4 pre-existing skips)🤖 Generated with Claude Code
Summary by CodeRabbit