-
- Notifications
You must be signed in to change notification settings - Fork 22
Cached keypairs #1366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Cached keypairs #1366
Conversation
Walkthrough
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/dispatchers.ts (1)
117-128: Cache population logic is correct, but consider the architectural context.The keypair construction and caching logic is implemented correctly. However, note that this adds module-level state to a file marked as legacy that should be refactored into class-based handlers (see TODO comment at top).
As per the coding guidelines: "Do not add new legacy factory handlers to dispatchers.ts (legacy file)". While this doesn't add a new handler, it adds persistent state to a file that should be migrated to a class-based architecture. When refactoring this file (as noted in the TODO), ensure the caching mechanism is incorporated into the class-based design with proper lifecycle management.
Minor optimization note: Concurrent requests for the same
account.idwill race to populate the cache, performing duplicateimportJwkwork. While not a correctness issue, a per-key lock or once-per-key mechanism could prevent this. However, this is a low-priority optimization.Based on coding guidelines.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/dispatchers.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Never use direct string comparisons for ActivityPub IDs; use SHA256 hash-based lookups instead
Use Result helper functions (isError, getError, getValue) and avoid destructuring Result values directly
Awilix uses CLASSIC injection: constructor parameter names must match their registration names
Define routes using decorators rather than direct registration
Prefer immutable entities that emit domain events over mutable entities with dirty flags
Use structured error objects with context in Result types instead of string literals
Prefer class-based handlers with dependency injection over function factories
Files:
src/dispatchers.ts
src/dispatchers.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not add new legacy factory handlers to dispatchers.ts (legacy file)
Files:
src/dispatchers.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build / Build Docker Images (linux/amd64, amd64)
🔇 Additional comments (1)
src/dispatchers.ts (1)
111-114: Cache check logic is correct.The early return optimization correctly reduces redundant
importJwkcalls. However, its effectiveness depends on addressing the cache invalidation and memory concerns flagged above.
| import type { PostService } from '@/post/post.service'; | ||
| import type { SiteService } from '@/site/site.service'; | ||
| | ||
| const keypairCache = new Map<number, CryptoKeyPair>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add cache invalidation and size limits.
The module-level cache has two critical concerns:
- No invalidation mechanism: If account keypairs are rotated or updated in the database, the cached versions will be used indefinitely, potentially causing authentication failures or security issues.
- Unbounded growth: The cache will accumulate entries for every account that makes a request, leading to a memory leak in long-running processes.
Consider implementing:
- A cache invalidation strategy triggered by account updates/key rotations
- An LRU cache with a maximum size, or TTL-based expiration
- A more sophisticated caching solution like
node-cacheorlru-cache
-const keypairCache = new Map<number, CryptoKeyPair>(); +// TODO: Implement proper cache with invalidation and size limits +// Consider using an LRU cache library or adding TTL-based expiration +const keypairCache = new Map<number, CryptoKeyPair>();Would you like me to generate an implementation using an LRU cache with configurable size limits?
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/dispatchers.ts around line 46 the module-level Map lacks invalidation and size limits; replace it with a bounded, TTL-capable LRU cache (or integrate lru-cache or node-cache) configured by an env/const maxSize and optional ttl, use the account ID as key and store CryptoKeyPair values; add API functions to delete a single entry and to clear the cache for account-update/key-rotation flows, and call those invalidation functions from any code path that updates or rotates keys (or subscribe to account-update events) so stale keypairs are removed; ensure cache operations are thread-safe and avoid storing extra sensitive metadata. aa3adf4 to 1c3fadc Compare 1c3fadc to a05edfe Compare ref https://linear.app/ghost/issue/PROD-2541 - `importJwk` and `JSON.parse` are CPU intensive operations and the workload is using them on every request. This change caches these operations and avoids unnecessary CPU usage.
a05edfe to e3ecd96 Compare
ref https://linear.app/ghost/issue/PROD-2541
importJwkandJSON.parseare CPU intensive operations and the workload is using them on every request. This change caches these operations and avoids unnecessary CPU usage.