Stubbed AdapterCacheRedis.keys() with an IncorrectUsageError#27465
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThe 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
ghost/core/core/server/adapters/lib/redis/AdapterCacheRedis.js (1)
274-278: Docstring overstates_keys()role in reset flowThe comment says
_keys()is preserved for reset flow, butreset()currently uses#getKeys()directly (Line 257). Tightening this wording will avoid confusion during later cleanup.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/core/core/server/adapters/lib/redis/AdapterCacheRedis.js` around lines 274 - 278, The docstring for _keys() is misleading because reset() calls getKeys() directly rather than relying on _keys(); update the comment above AdapterCacheRedis._keys() to remove the claim that it’s preserved for the SCAN-based reset() flow and instead state that _keys() is deprecated/kept only for backward compatibility (or legacy SCAN implementations) while reset() currently uses getKeys(); reference the symbols _keys(), getKeys(), and reset() in the updated wording so future readers understand the actual call-path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ghost/core/core/server/adapters/lib/redis/AdapterCacheRedis.js`:
- Around line 280-284: The keys() method in AdapterCacheRedis is declared async
so throwing there produces a rejected Promise instead of a synchronous throw;
change the method signature to a synchronous function (remove the async keyword
from AdapterCacheRedis.prototype.keys / keys()) so it throws IncorrectUsageError
immediately for sync callers (e.g., cache-manager.js using const keys =
this.settingsCache.keys()), ensuring the intended error is raised instead of a
TypeError from calling forEach on a Promise.
---
Nitpick comments:
In `@ghost/core/core/server/adapters/lib/redis/AdapterCacheRedis.js`:
- Around line 274-278: The docstring for _keys() is misleading because reset()
calls getKeys() directly rather than relying on _keys(); update the comment
above AdapterCacheRedis._keys() to remove the claim that it’s preserved for the
SCAN-based reset() flow and instead state that _keys() is deprecated/kept only
for backward compatibility (or legacy SCAN implementations) while reset()
currently uses getKeys(); reference the symbols _keys(), getKeys(), and reset()
in the updated wording so future readers understand the actual call-path.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 83ba2b2f-63df-4137-8e24-7215d8089e8f
📒 Files selected for processing (1)
ghost/core/core/server/adapters/lib/redis/AdapterCacheRedis.js
ca1c409 to
432727f
Compare
ref no-issue The cache adapter interface (@tryghost/adapter-base-cache) still requires a keys() method, but enumerating every key in redis is an O(n) SCAN that no production code path should rely on - the previous consumer was settings-cache.getAll(), which calls keys() synchronously and treats the result as an array. The redis impl was async, so any deployment that wired Redis to the settings cache would already crash on keys.forEach is not a function. The path is unreachable in practice but worth tightening up. The stub is sync (not async) so the throw surfaces directly to the same sync caller pattern that exposed the original bug, instead of becoming an unhandled rejection. A future bump to @tryghost/adapter-base-cache that drops keys from requiredFns will let us remove the stub entirely.
432727f to
23b605a
Compare
|



Why
AdapterCacheRedis.keys()is async — it has to be, since it's an O(n) SCAN against redis — but its only consumer,settings-cache.getAll(), calls it withoutawaitand treats the result as a sync array. So if anything ever wired Redis to the settings cache, everyGET /settingsandPUT /settingswould crash withkeys.forEach is not a function. Nothing does today, so the path is unreachable, but it's a latent footgun.The method is also documented as transitional in
@tryghost/adapter-base-cache:We can't just delete
keys()though.BaseCacheAdapter.requiredFns(defined in the external package) lists it, andadapter-managervalidates every loaded adapter against that list. Removing the method would crash Ghost at boot.So this PR swaps the public
keys()for a stub that throwsIncorrectUsageError. The stub is intentionally sync, not async, so the throw surfaces directly to the same sync caller pattern that exposed the original bug, rather than becoming an unhandled rejection.Cleanup path (follow-up, not in this PR)
settings-cache.getAll()so it no longer depends oncacheStore.keys().@tryghost/adapter-base-cacheto drop"keys"fromrequiredFns, then delete the stub.reset()lands, the SCAN helpers (#getKeys,#scanNodeForKeys,#getPrimaryRedisNode) become dead and can go too.Notes for reviewers
cache.keys()throwsIncorrectUsageErrorsynchronously.AdapterCacheRedisunit tests still pass; an additional unit test asserts the throw.