fix(clerk-js): Fix token cache refresh timer leak#8098
fix(clerk-js): Fix token cache refresh timer leak#8098jacekradko wants to merge 8 commits intomainfrom
Conversation
When set() was called multiple times for the same cache key, old refresh and expiration timers were never cancelled. This caused orphaned timers to accumulate — each independently firing onRefresh — making the poller appear erratic with accelerating token refresh requests. The root cause: both _updateClient (via Session constructor → #hydrateCache) and #refreshTokenInBackground call set() for the same key during a single refresh cycle. Each set() created new timers without clearing the old ones. After N cycles, N orphaned timers all fire at different offsets. Fix: clear existing timers at the start of setInternal before creating the new cache entry.
🦋 Changeset detectedLatest commit: c0f0f3d The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
@clerk/agent-toolkit
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/dev-cli
@clerk/expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughClears prior refresh and expiration timers before updating entries in 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📝 Coding Plan
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/clerk-js/src/core/tokenCache.ts`:
- Around line 353-364: The cache set flow currently only clears timers on
existing entries but doesn't prevent a pending tokenResolver promise from later
installing orphaned refresh timers or invoking onRefresh after the key has been
overwritten; update the logic in the tokenCache set/update paths (the code that
constructs/assigns entries with tokenResolver, timeoutId, refreshTimeoutId and
that installs refresh timers and calls onRefresh) to attach a unique
marker/version id to each cache entry (e.g., entry.version or entry.resolverId)
when creating it and, before installing any timers or invoking onRefresh inside
tokenResolver.then/Promise continuations, verify the stored marker still matches
the current cache entry for that key—if it does not match, bail out and do not
set refreshTimeoutId or call onRefresh; apply the same guard wherever
tokenResolver continuations create timers (the other block that handles
refreshTimeoutId) so pending resolvers cannot schedule orphaned refreshes after
an overwrite.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9af73399-f0a6-4ae4-810d-636541e51793
📒 Files selected for processing (4)
.changeset/fix-token-cache-timer-leak.mdintegration/tests/session-token-cache/refresh-timer-cleanup.test.tspackages/clerk-js/src/core/__tests__/tokenCache.test.tspackages/clerk-js/src/core/tokenCache.ts
Summary
SessionTokenCachethat caused token refresh requests to fire much earlier than expectedset()is called multiple times for the same cache key (from_updateClienthydration AND#refreshTokenInBackground), old timers were never cleared — each leaked timer independently firedonRefresh, accelerating the effective polling ratesetInternalbefore creating the new cache entrysession.touch()or any API response that triggers_updateClientTest plan
session.touch()Summary by CodeRabbit
Bug Fixes
Tests