Skip to content

feat(news): server-side feed aggregation to cut Vercel costs ~70-95%#622

Merged
koala73 merged 2 commits into
mainfrom
feat/rss-feed-cost-reduction
Mar 1, 2026
Merged

feat(news): server-side feed aggregation to cut Vercel costs ~70-95%#622
koala73 merged 2 commits into
mainfrom
feat/rss-feed-cost-reduction

Conversation

@koala73

@koala73 koala73 commented Mar 1, 2026

Copy link
Copy Markdown
Owner

Summary

Addresses the root cause of ~$5,740/10-day Vercel bill by eliminating redundant RSS feed fetching:

  • Phase 1 — CDN caching fix: api/rss-proxy.js was passing upstream Cache-Control headers (often no-cache/private) through to Vercel CDN, defeating edge caching. Now forces s-maxage=300 on 2xx, short TTLs on errors, plus CDN-Cache-Control header.
  • Phase 2 — Server-side aggregation: New ListFeedDigest RPC aggregates ALL feeds for a variant into a single Redis-cached response. Client makes 1 request instead of ~90 per cycle. Includes circuit breaker with persistent cache fallback.
  • Phase 3 — Polling interval: Increased from 5min to 7min to offset CDN cache TTL alignment.

Key changes

File Change
api/rss-proxy.js Force CDN cache headers on 2xx responses
proto/.../list_feed_digest.proto New proto + source field on ThreatClassification
server/.../list-feed-digest.ts Server handler: bounded concurrency, per-feed Redis cache, XML regex parsing
server/.../_feeds.ts Server-side feed config (4 variants + intel sources)
server/.../_classifier.ts Self-contained keyword classifier for server-side use
src/app/data-loader.ts Digest consumer: circuit breaker, persistent fallback, AI reclassification parity
src/services/ai-classify-queue.ts Extracted AI queue logic (shared by rss.ts and data-loader.ts)
src/config/variants/base.ts Feed polling: 5min → 7min

Estimated impact

Phase Edge Requests Data Transfer
Phase 1 (CDN fix) -30% -70%
Phase 2 (aggregation) -90% -85%
Phase 3 (polling) -30% additional -30% additional
Combined ~95% ~90%

Test plan

  • tsc --noEmit — 0 errors
  • route-cache-tier.test.mjs — 3/4 pass (1 pre-existing: list-iran-events missing)
  • edge-functions.test.mjs — 28/28 pass
  • Deploy to preview → verify single /api/news/v1/list-feed-digest request in Network tab
  • Verify CDN hit ratio on rss-proxy goes from ~0% to >90% in Vercel Analytics
  • Monitor Vercel billing dashboard 24-48h after deploy

…y ~95%

Phase 1: Force CDN caching on rss-proxy (s-maxage=300 for 2xx, short
TTL for errors) — fixes bug where upstream no-cache headers were passed
through verbatim, defeating Vercel CDN.

Phase 2: Add ListFeedDigest RPC that aggregates all feeds server-side
into a single Redis-cached response. Client makes 1 request instead of
~90 per cycle. Includes circuit breaker with persistent cache fallback,
per-feed AI reclassification, and headline ingestion parity.

Phase 3: Increase polling interval from 5min to 7min to offset CDN
cache alignment.

New files:
- proto/worldmonitor/news/v1/list_feed_digest.proto
- server/worldmonitor/news/v1/{_feeds,_classifier,list-feed-digest}.ts
- src/services/ai-classify-queue.ts (extracted from rss.ts)
@vercel

vercel Bot commented Mar 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Mar 1, 2026 1:12am
worldmonitor-finance Ready Ready Preview, Comment Mar 1, 2026 1:12am
worldmonitor-happy Ready Ready Preview, Comment Mar 1, 2026 1:12am
worldmonitor-startup Ready Ready Preview, Comment Mar 1, 2026 1:12am

Request Review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Take main's 'static' tier for list-airport-delays.
@koala73
koala73 merged commit eceeb6b into main Mar 1, 2026
6 checks passed
koala73 added a commit that referenced this pull request Mar 1, 2026
PR #622 (server-side feed aggregation) only ported 8 of 14 finance
categories to VARIANT_FEEDS. The 6 omitted categories (derivatives,
fintech, regulation, institutional, analysis, gccNews) caused
"UNAVAILABLE" panels on finance.worldmonitor.app.

Restores all feeds to match the pre-migration frontend config exactly.
Also adds missing public/favico/finance/ directory (404s on favicon).
koala73 added a commit that referenced this pull request Mar 1, 2026
PR #622 (server-side feed aggregation) only ported 8 of 14 finance
categories to VARIANT_FEEDS. The 6 omitted categories (derivatives,
fintech, regulation, institutional, analysis, gccNews) caused
"UNAVAILABLE" panels on finance.worldmonitor.app.

Restores all feeds to match the pre-migration frontend config exactly.
Also adds missing public/favico/finance/ directory (404s on favicon).
koala73 added a commit that referenced this pull request Mar 1, 2026
#654)

PR #622 (server-side feed aggregation) only ported 8 of 14 finance
categories to VARIANT_FEEDS. The 6 omitted categories (derivatives,
fintech, regulation, institutional, analysis, gccNews) caused
"UNAVAILABLE" panels on finance.worldmonitor.app.

Restores all feeds to match the pre-migration frontend config exactly.
Also adds missing public/favico/finance/ directory (404s on favicon).
koala73 added a commit that referenced this pull request Mar 1, 2026
…y ~95% (#622)

Phase 1: Force CDN caching on rss-proxy (s-maxage=300 for 2xx, short
TTL for errors) — fixes bug where upstream no-cache headers were passed
through verbatim, defeating Vercel CDN.

Phase 2: Add ListFeedDigest RPC that aggregates all feeds server-side
into a single Redis-cached response. Client makes 1 request instead of
~90 per cycle. Includes circuit breaker with persistent cache fallback,
per-feed AI reclassification, and headline ingestion parity.

Phase 3: Increase polling interval from 5min to 7min to offset CDN
cache alignment.

New files:
- proto/worldmonitor/news/v1/list_feed_digest.proto
- server/worldmonitor/news/v1/{_feeds,_classifier,list-feed-digest}.ts
- src/services/ai-classify-queue.ts (extracted from rss.ts)
koala73 added a commit that referenced this pull request Mar 1, 2026
#654)

PR #622 (server-side feed aggregation) only ported 8 of 14 finance
categories to VARIANT_FEEDS. The 6 omitted categories (derivatives,
fintech, regulation, institutional, analysis, gccNews) caused
"UNAVAILABLE" panels on finance.worldmonitor.app.

Restores all feeds to match the pre-migration frontend config exactly.
Also adds missing public/favico/finance/ directory (404s on favicon).
matthewvecchione1-ops pushed a commit to matthewvecchione1-ops/worldmonitor that referenced this pull request Mar 4, 2026
…y ~95% (koala73#622)

Phase 1: Force CDN caching on rss-proxy (s-maxage=300 for 2xx, short
TTL for errors) — fixes bug where upstream no-cache headers were passed
through verbatim, defeating Vercel CDN.

Phase 2: Add ListFeedDigest RPC that aggregates all feeds server-side
into a single Redis-cached response. Client makes 1 request instead of
~90 per cycle. Includes circuit breaker with persistent cache fallback,
per-feed AI reclassification, and headline ingestion parity.

Phase 3: Increase polling interval from 5min to 7min to offset CDN
cache alignment.

New files:
- proto/worldmonitor/news/v1/list_feed_digest.proto
- server/worldmonitor/news/v1/{_feeds,_classifier,list-feed-digest}.ts
- src/services/ai-classify-queue.ts (extracted from rss.ts)
matthewvecchione1-ops pushed a commit to matthewvecchione1-ops/worldmonitor that referenced this pull request Mar 4, 2026
koala73#654)

PR koala73#622 (server-side feed aggregation) only ported 8 of 14 finance
categories to VARIANT_FEEDS. The 6 omitted categories (derivatives,
fintech, regulation, institutional, analysis, gccNews) caused
"UNAVAILABLE" panels on finance.worldmonitor.app.

Restores all feeds to match the pre-migration frontend config exactly.
Also adds missing public/favico/finance/ directory (404s on favicon).
@koala73
koala73 deleted the feat/rss-feed-cost-reduction branch March 4, 2026 19:40
Yachtman25 added a commit to Dabblecraft2DevTeam/worldmonitor that referenced this pull request Mar 12, 2026
Yachtman25 added a commit to Dabblecraft2DevTeam/worldmonitor that referenced this pull request Mar 12, 2026
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