Repository navigation
perf(bot): bound external scrobbler track cache with lru+ttl (#1282) - #1316
Conversation
lastExternalTrack was a bare Map keyed by guild id with no eviction — it grew unbounded in a long-lived process when external bots go silent. Swap to LRUCache (max 10000, ttl 10min); get/set/delete semantics are unchanged, so scrobble dedup behavior is identical (existing spec).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
Warning Review limit reached
More reviews will be available in 55 minutes and 14 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 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 |
|
Failed to generate code suggestions for PR |
There was a problem hiding this comment.
No issues found across 1 file
Auto-approved: Swaps an unbounded Map to an LRU cache with TTL for external scrobbler track dedup. The change is functionally identical, uses an existing dependency, and prevents memory growth.
Re-trigger cubic
|
🤖 I have created a release *beep* *boop* --- <details><summary>2.18.0</summary> ## [2.18.0](v2.17.0...v2.18.0) (2026-06-19) ### Features * **autoplay:** add implicit-dislike-penalty signal ([#1374](#1374)) ([593c0ad](593c0ad)) * **autoplay:** add recency-decay signal for queue diversity ([#1376](#1376)) ([b85e2a0](b85e2a0)) * **autoplay:** boost candidates for frequently replayed tracks ([#1370](#1370)) ([215edea](215edea)) * **autoplay:** guild opt-out toggle for sertanejo veto ([#1087](#1087)) ([#1373](#1373)) ([6cb5588](6cb5588)) * **autoplay:** instrument outcome eval to disambiguate [#1275](#1275) ([#1491](#1491)) ([1921ab5](1921ab5)) * **backend:** add zod validation to artists and toggles routes ([#1189](#1189)) ([#1334](#1334)) ([b59fb35](b59fb35)) * **backend:** dedup key for support-report intake ([#1319](#1319)) ([#1328](#1328)) ([4d95307](4d95307)) * **backend:** move session store from Redis to Postgres ([#1111](#1111)) ([#1396](#1396)) ([ff5e0b6](ff5e0b6)) * **backend:** request-id correlation middleware for [#1286](#1286) ([#1417](#1417)) ([671ed4c](671ed4c)) * **bot:** instrument serversetup criativaria invocations ([#1288](#1288)) ([#1390](#1390)) ([c37f021](c37f021)) * **bot:** utility join-onboarding message + in-bot growth adr ([#1506](#1506)) ([0a23775](0a23775)) * **db:** add check constraints on guild_settings bounds ([#1124](#1124)) ([#1338](#1338)) ([a7c7400](a7c7400)) * growth surfaces — /invite, landing SEO + CTA, guild telemetry ([#1494](#1494)) ([205876d](205876d)) * **music:** add previous-track command end to end ([#1239](#1239)) ([#1347](#1347)) ([7771167](7771167)) * **observability:** alert on redis control publish failures ([#1401](#1401)) ([6e46cd7](6e46cd7)) * **security:** add security headers + csp report-only ([#1283](#1283)) ([#1315](#1315)) ([7413a1c](7413a1c)) * **security:** collect CSP violations via report-uri sink ([#1283](#1283)) ([#1415](#1415)) ([6f68aa3](6f68aa3)) * skip-reason telemetry via emoji reactions on now-playing ([#1377](#1377)) ([5b1959f](5b1959f)) ### Bug Fixes * add timeouts to unbounded external fetch calls ([#1333](#1333)) ([38dde55](38dde55)) * **auth:** log session lookup failures in optional auth ([#1286](#1286)) ([ff2b3ab](ff2b3ab)) * **autoplay:** capture skip rejections (symmetric completion threshold) ([#1276](#1276)) ([c282414](c282414)) * **autoplay:** key track start-time per track, not per guild ([#1275](#1275)) ([#1483](#1483)) ([0853a90](0853a90)) * **autoplay:** provenance-aware genre guards open the seed neighborhood ([#1272](#1272)) ([405af1e](405af1e)) * **autoplay:** weight popularity over name similarity in similar mode ([#1273](#1273)) ([cb24a7e](cb24a7e)) * **backend:** bound pagination limit on leaderboard + starboard entries ([#1307](#1307)) ([c2b5cbe](c2b5cbe)) * **backend:** degrade gracefully on external fetch timeouts ([#1342](#1342)) ([#1345](#1345)) ([5de7b69](5de7b69)) * **backend:** log swallowed spotify search errors ([#1285](#1285)) ([#1318](#1318)) ([72a7431](72a7431)) * **backend:** replayed named creates return existing row ([#1320](#1320)) ([#1326](#1326)) ([be2b30c](be2b30c)) * **backend:** validate guildId snowflake on all 18 music routes ([#1297](#1297)) ([b93cfb5](b93cfb5)) * **bot:** accurate reply when previous button has no history ([#1191](#1191)) ([#1331](#1331)) ([eb9b2ea](eb9b2ea)) * **bot:** bound all Spotify API fetches with an 8s abort deadline ([#1302](#1302)) ([b283159](b283159)) * **bot:** catch resume errors in skip delayed play ([#1353](#1353)) ([#1354](#1354)) ([c2d2758](c2d2758)) * **bot:** catch settings fetch errors in idle disconnect scheduling ([#1361](#1361)) ([61b82e4](61b82e4)) * **bot:** extend graceful bot-perm guard to mgmt + automod ([#1502](#1502)) ([1ee510d](1ee510d)) * **bot:** graceful bot-permission guard + moderation pilot ([#1498](#1498)) ([#1499](#1499)) ([e2664ce](e2664ce)) * **bot:** harden youtube extractor registration ([#1468](#1468)) ([#1472](#1472)) ([2e7f1bb](2e7f1bb)) * **bot:** queue summary position is milliseconds, not seconds ([#1202](#1202)) ([#1330](#1330)) ([efa9800](efa9800)) * **bot:** skip startup session restore into empty voice channel ([#1469](#1469)) ([dbcc08c](dbcc08c)) * **bot:** thread real Client into endGiveaway ([#1383](#1383)) ([#1388](#1388)) ([d3b274a](d3b274a)) * **bot:** wire setupwebmusichandler at startup ([#1321](#1321)) ([#1351](#1351)) ([dc68e7e](dc68e7e)) * **ci:** grant review-tools caller the scopes its reusables require ([#1424](#1424)) ([c215675](c215675)) * **ci:** quality/Lint green again — core rules off for bot/shared at root lint ([#1364](#1364)) ([#1365](#1365)) ([cc2322f](cc2322f)) * **compose:** tag container logs so loki labels them by name ([#1476](#1476)) ([4e956df](4e956df)) * **deps:** bump multer to 2.2.0 to fix high-severity dos advisory ([#1493](#1493)) ([4d57ac8](4d57ac8)) * **deps:** bump qs to 6.15.2 and hono to 4.12.25 (audit) ([#1295](#1295)) ([ae5d949](ae5d949)) * **deps:** pin piscina 4.9.3 for high-severity rce advisory ([#1504](#1504)) ([10b68e6](10b68e6)) * **docker:** add C toolchain to deps-production for opus source-build fallback ([#1310](#1310)) ([5ed7f11](5ed7f11)) * **download:** drop invalid --extract-flat flag from yt-dlp download ([#1488](#1488)) ([9d29144](9d29144)) * **frontend:** default add-to-discord cta to public application id ([#1495](#1495)) ([efda71e](efda71e)) * **help:** split large command categories across embed fields ([#1489](#1489)) ([0fa5786](0fa5786)) * **player:** warn not error on bridge exhaustion for unplayable tracks ([#1507](#1507)) ([d7a4a58](d7a4a58)) * **security:** bump vite 8.0.16 + form-data 4.0.6 for high advisories ([#1457](#1457)) ([58d21d5](58d21d5)) * **shared:** env-isolate environment.test.ts (no secret dumps) ([#1292](#1292)) ([588037c](588037c)) * **shared:** log db error in feature-toggle override read ([#1286](#1286)) ([#1411](#1411)) ([0dfc409](0dfc409)) * **shared:** make read-then-write service paths atomic ([#1199](#1199)) ([#1340](#1340)) ([ba1b840](ba1b840)) * **shared:** normalize embed template name on gettemplate ([#1327](#1327)) ([#1350](#1350)) ([d221b57](d221b57)) * **shared:** safe env parsing via parseIntEnv helper ([#1209](#1209)) ([#1335](#1335)) ([32e3684](32e3684)) * **shared:** validate guildautomation json on read ([#1194](#1194)) ([#1346](#1346)) ([93d9eea](93d9eea)) * **spotify:** log oauth token-exchange failures ([#1286](#1286) track b) ([8306c35](8306c35)) * **twitch:** re-subscribe to EventSub after unexpected reconnect ([#870](#870)) ([#1395](#1395)) ([78a30f3](78a30f3)) * **twitch:** refresh bot subscriptions on web add/remove ([#870](#870)) ([939d4b3](939d4b3)) * **web:** clear auth check promise on settle, not via 100ms timer ([#1311](#1311)) ([5cc8eef](5cc8eef)) * **web:** report swallowed member-context fetch error to Sentry ([#1286](#1286) B3) ([#1416](#1416)) ([85f141d](85f141d)) * **web:** route handled errors to Sentry, enforce no-console ([#1296](#1296)) ([a34e777](a34e777)) ### Performance Improvements * **bot:** bound external scrobbler track cache with lru+ttl ([#1282](#1282)) ([#1316](#1316)) ([7f29efc](7f29efc)) * **shared:** batch recommendation telemetry counts in one groupBy ([#1308](#1308)) ([e5a5973](e5a5973)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Release 2.18.0 with smarter autoplay, a previous-track command, stronger security/telemetry, and Postgres-backed sessions. This improves stability across the bot, backend, and web apps. - **New Features** - Smarter autoplay with new ranking signals (implicit dislike, recency decay, replay boost), a guild opt-out, and outcome/skip telemetry. - Previous-track command end to end. - Security headers and CSP report-only with violation collection. - Session store moved from Redis to Postgres plus request-id correlation middleware. - **Bug Fixes** - Add timeouts and graceful fallbacks for external calls; bound pagination limits and validate guild IDs. - Harden bot behavior: permission guards, YouTube extractor registration, correct queue position and previous-button messaging, skip session restore into empty channels. - Improve observability: route handled errors to Sentry, surface swallowed errors, alert on Redis publish failures. - Security updates to dependencies (`multer`, `qs`, `hono`, `vite`, `form-data`) and pin `piscina`; add a C toolchain in Docker for opus fallback. <sup>Written for commit d28bef3. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/LucasSantana-Dev/Lucky/pull/1508?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->



What
lastExternalTrackinpackages/bot/src/handlers/externalScrobbler.tswas a bareMapkeyed by guild id with no eviction or TTL — unbounded growth in a long-lived bot process (same bug class as the #1206 sweep; this site was missed).Swapped to
LRUCache(already a bot dependency,lru-cache@^11.5.0) withmax: 10000, ttl: 10minper the issue's acceptance criteria.get/set/deletesemantics are unchanged, so scrobble dedup behavior is identical — covered by the existing spec (5/5 green).A track idle past the TTL is no longer scrobble-worthy anyway (the scrobble path already requires the next now-playing message to arrive; a 10-min-stale entry means the external bot stopped playing).
Closes #1282
Summary by cubic
Bound the external scrobbler per-guild track cache with an LRU+TTL to stop unbounded memory growth in long-lived bot processes. Swapped the plain Map for
lru-cache(max 10,000, TTL 10 min); cache ops and scrobble dedup behavior remain the same.Written for commit c067cca. Summary will update on new commits.