Repository navigation
perf(service): cut request overhead and serve now playing as a CDN-cached shared read - #3182
Conversation
Browsers re-sent the preflight for every oRPC POST because the CORS response carried no Access-Control-Max-Age; cache it for 7200s, the Chromium cap. pg's 10s idle timeout closed the pool between most requests at this traffic (~506 new connections per ~820 RPC calls a day, ~25ms each). Keep idle clients for 5 minutes, with allowExitOnIdle so one-shot scripts such as migrate.ts still exit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
spotify.playing is the same for every visitor, so it no longer rides the per-visitor POST path: - shared/shared-reads.ts lists procedures that answer every caller alike. service accepts GET only for those and marks a success with CDN-Cache-Control, browser Cache-Control: no-cache and Access-Control-Allow-Origin: *; the www link sends them as credential-less GETs, which need no preflight. - The output is a small DTO (track, isPlaying, progressMs, observedAt) instead of Spotify's raw payload. The browser advances progress from observedAt and refetches when the track should end. - service caches the DTO in Redis for 10s and treats a track that has ended as stale. A Cloudflare cache rule now makes GETs under /api/v1/rpc/ cacheable when the response carries cache headers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (3)No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (14)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe change adds a shared, cached Spotify playback read with a normalized response. It serves that read through credential-less GET requests with CDN headers and updates the playback display. It also changes PostgreSQL idle connection settings and CORS preflight caching. ChangesShared Spotify playback read
PostgreSQL connection settings
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Feature Sequence Diagram(s)sequenceDiagram
participant Browser
participant RpcHandler
participant SpotifyRoute
participant PlaybackService
participant Keyv
participant SpotifyAPI
Browser->>RpcHandler: GET spotify.playing
RpcHandler->>SpotifyRoute: Invoke playback route
SpotifyRoute->>PlaybackService: Pass database and KV contexts
PlaybackService->>Keyv: Read cached playback
alt Cache miss or cached track ended
PlaybackService->>SpotifyAPI: Fetch current playback
SpotifyAPI-->>PlaybackService: Return Spotify playback data
PlaybackService->>Keyv: Store normalized response
else Cached response is reusable
Keyv-->>PlaybackService: Return cached response
end
PlaybackService-->>SpotifyRoute: Return normalized playback
SpotifyRoute-->>RpcHandler: Return procedure result
RpcHandler-->>Browser: Return playback response
Merge Risk: ⚪ Minimal · up to The shared playback changes are mergeable after normal checks. Redis cache-write failures do not discard successful playback reads under the production configuration. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The shared read is restricted to playback metadata and does not depend on the visitor’s identity. However, switching or disconnecting the published Spotify account does not invalidate its cached response, so previously published metadata can remain available temporarily. Production CDN behavior has not been confirmed. Retained concerns
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 11 files. (3 skipped: 3 unsupported.)
✨ Finishing Touches 💡 1📝 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 |
Why
Production traces (Tempo 24h, Railway 7d) show
servicehandlers are fast —feeds.listp50 ~47ms,feeds.details-by-slugp50 ~120ms — and the time www sees goes to what surrounds them:Access-Control-Max-Age, so browsers re-preflight every oRPC POST (~288 OPTIONS/day, ~200ms each from Taipei).spotify.playing, the most-called procedure (289/day), hit api.spotify.com on every request and returned Spotify's raw payload, while every visitor polls the same data.Railway's p95/p99 of 30000ms are long-lived streams (
/api/v1/mcpSSE,feeds/draft:watch, agent chat), not slow requests.Changes
CORS and pool
cors()setsmaxAge: 7200(the Chromium cap).allowExitOnIdlesomigrate.ts, which never ends the pool, still exits.spotify.playingas a shared readNew
@chia/services/shared/shared-reads: procedures whose answer is the same for every caller, mapped to theCDN-Cache-Controla success carries. The module imports nothing, so both the handler and the browser link load it.serviceaccepts GET only for those (allowMethods). A successful GET carries:CDN-Cache-Control: max-age=10, stale-while-revalidate=50for Cloudflare (s-maxagewould turn off stale-while-revalidate there)Cache-Control: no-cachefor browsersAccess-Control-Allow-Origin: *without credentials, because a CDN stores one copy for every origin and ignoresVary: OriginThese are set through
c.header, because Hono copies the CORS headers set beforenextonto the returned response. Failures carry no cache headers.The www link sends shared reads as credential-less
GET …/spotify/playing?data=with no custom headers, so there is no preflight and every visitor shares one cache key.The contract returns
{ track, isPlaying, progressMs, observedAt }instead of Spotify's raw payload. The response isnullfor ads and podcasts.servicecaches the DTO in Redis for 10s and treats a track that has ended as stale.www advances progress from
observedAtand refetches when the track should end: at least 5s, so a stale edge copy cannot make it spin, and at most 60s, so skips and pauses still show. This replaces the progress context and the end-of-track refetch loop.Cloudflare (already applied)
service.chia1104.devunder/api/v1/rpc/are cache-eligible. The edge follows the response's cache headers and bypasses the cache when there are none. Checked against current production: the GET still gets 404 +BYPASS, and POST and health stayDYNAMIC.Deploy notes
spotify.playingresponse shape changed and there is no compatibility layer. Until both sides are deployed, and in tabs still running the old www bundle, the footer now-playing widget errors until reload.GET https://service.chia1104.dev/api/v1/rpc/spotify/playing?data=. Expectcf-cache-statusMISS, thenHITwithin 10s andUPDATINGfrom 10 to 60s.BYPASSwould mean Cloudflare is not readingCDN-Cache-Control.pg.connectper RPC call, and api.spotify.com calls underspotify.playing.Tests
apps/service: 129 passed, 1 skipped. New cases cover the DTO mapping,nullfor ads, the shared cache window, refetch after the track ends, GET headers (CDN + browser + CORS), no cache headers on POST or a failed GET, and 404 for GET on a procedure that is not a shared read.@chia/services133,@chia/db,@chia/service-kitandwwwtests pass.--forcepass fordb,service-kit,services,service,workflow-serviceandwww.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes