-
Notifications
You must be signed in to change notification settings - Fork 1
Add regex & memoize caches; optimize queries #524
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: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -53,6 +53,11 @@ const DB_DUPLICATE_KEY_ERROR = '11000'; | |||
| */ | ||||
| const MAX_CODE_LINE_LENGTH = 140; | ||||
|
|
||||
| /** | ||||
| * TTL for repetition cache lookups in seconds | ||||
| */ | ||||
| const REPETITION_CACHE_TTL = 300; | ||||
|
|
||||
| /** | ||||
| * Worker for handling Javascript events | ||||
| */ | ||||
|
|
@@ -87,6 +92,11 @@ export default class GrouperWorker extends Worker { | |||
| */ | ||||
| private cacheCleanupInterval: NodeJS.Timeout | null = null; | ||||
|
|
||||
| /** | ||||
| * Cache for compiled RegExp patterns to avoid repeated compilation | ||||
| */ | ||||
| private regexpCache = new Map<string, RegExp>(); | ||||
|
|
||||
| /** | ||||
| * Start consuming messages | ||||
| */ | ||||
|
|
@@ -131,6 +141,35 @@ export default class GrouperWorker extends Worker { | |||
| await this.redis.close(); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Override clearCache to also clear memoization caches and RegExp cache | ||||
| * This prevents memory leaks from decorator-based LRU caches | ||||
| */ | ||||
| public clearCache(): void { | ||||
| super.clearCache(); | ||||
|
|
||||
| /** | ||||
| * Clear RegExp cache | ||||
| */ | ||||
| this.regexpCache.clear(); | ||||
|
|
||||
| /** | ||||
| * Clear memoization caches from decorators | ||||
| * These are stored as properties on the instance | ||||
| */ | ||||
| const memoizeCachePrefix = 'memoizeCache:'; | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Anyway, I don't see any reason to clear memoization cache manually:
|
||||
|
|
||||
| Object.keys(this).forEach(key => { | ||||
| if (key.startsWith(memoizeCachePrefix)) { | ||||
| const cache = this[key] as any; | ||||
|
|
||||
| if (cache && typeof cache.reset === 'function') { | ||||
| cache.reset(); | ||||
| } | ||||
| } | ||||
| }); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Task handling function | ||||
| * | ||||
|
|
@@ -156,7 +195,7 @@ export default class GrouperWorker extends Worker { | |||
| const similarEvent = await this.findSimilarEvent(task.projectId, task.payload.title); | ||||
|
|
||||
| if (similarEvent) { | ||||
| this.logger.info(`similar event: ${JSON.stringify(similarEvent)}`); | ||||
| this.logger.info(`similar event found: groupHash=${similarEvent.groupHash}, totalCount=${similarEvent.totalCount}`); | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lets also print projectId and event payload.title. |
||||
|
|
||||
| /** | ||||
| * Override group hash with found event's group hash | ||||
|
|
@@ -386,7 +425,7 @@ export default class GrouperWorker extends Worker { | |||
| try { | ||||
| const originalEvent = await this.findFirstEventByPattern(matchingPattern.pattern, projectId); | ||||
|
|
||||
| this.logger.info(`original event for pattern: ${JSON.stringify(originalEvent)}`); | ||||
| this.logger.info(`original event for pattern found: groupHash=${originalEvent?.groupHash || 'none'}`); | ||||
|
|
||||
| if (originalEvent) { | ||||
| return originalEvent; | ||||
|
|
@@ -416,7 +455,12 @@ export default class GrouperWorker extends Worker { | |||
| } | ||||
|
|
||||
| return patterns.filter(pattern => { | ||||
| const patternRegExp = new RegExp(pattern.pattern); | ||||
| let patternRegExp = this.regexpCache.get(pattern.pattern); | ||||
|
|
||||
| if (!patternRegExp) { | ||||
| patternRegExp = new RegExp(pattern.pattern); | ||||
| this.regexpCache.set(pattern.pattern, patternRegExp); | ||||
| } | ||||
|
|
||||
| return title.match(patternRegExp); | ||||
| }).pop() || null; | ||||
|
|
@@ -428,6 +472,7 @@ export default class GrouperWorker extends Worker { | |||
| * @param projectId - id of the project to find related event patterns | ||||
| * @returns {ProjectEventGroupingPatternsDBScheme[]} EventPatterns object with projectId and list of patterns | ||||
| */ | ||||
| @memoize({ max: 100, ttl: MEMOIZATION_TTL, strategy: 'hash' }) | ||||
|
||||
| @memoize({ max: 100, ttl: MEMOIZATION_TTL, strategy: 'hash' }) |
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.
I don't see any reason to add @memoize to getProjectPatterns() since it is called only inside findSimilarEvent() which is memoized itself.
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.
In clearCache(),
for (const key in this)iterates enumerable properties including any enumerable properties on the prototype chain. UsingObject.keys(this)/Object.getOwnPropertyNames(this)would avoid unexpected prototype enumeration and make the cache-clearing logic more predictable.