@@ -6,7 +6,7 @@ import { Worker } from '../../../lib/worker';
66import * as WorkerNames from '../../../lib/workerNames' ;
77import * as pkg from '../package.json' ;
88import type { GroupWorkerTask , RepetitionDelta } from '../types/group-worker-task' ;
9- import type { EventAddons , EventDataAccepted , GroupedEventDBScheme } from '@hawk.so/types' ;
9+ import type { EventAddons , EventDataAccepted , GroupedEventDBScheme , BacktraceFrame , SourceCodeLine } from '@hawk.so/types' ;
1010import type { RepetitionDBScheme } from '../types/repetition' ;
1111import { DatabaseReadWriteError , DiffCalculationError , ValidationError } from '../../../lib/workerErrors' ;
1212import { decodeUnsafeFields , encodeUnsafeFields } from '../../../lib/utils/unsafeFields' ;
@@ -17,12 +17,18 @@ import RedisHelper from './redisHelper';
1717import levenshtein from 'js-levenshtein' ;
1818import { computeDelta } from './utils/repetitionDiff' ;
1919import TimeMs from '../../../lib/utils/time' ;
20+ import { rightTrim } from '../../../lib/utils/string' ;
2021
2122/**
2223 * Error code of MongoDB key duplication error
2324 */
2425const DB_DUPLICATE_KEY_ERROR = '11000' ;
2526
27+ /**
28+ * Maximum length for backtrace code line or title
29+ */
30+ const MAX_CODE_LINE_LENGTH = 140 ;
31+
2632/**
2733 * Worker for handling Javascript events
2834 */
@@ -118,6 +124,11 @@ export default class GrouperWorker extends Worker {
118124
119125 let incrementDailyAffectedUsers = false ;
120126
127+ /**
128+ * Trim source code lines to prevent memory leaks
129+ */
130+ this . trimSourceCodeLines ( task . event ) ;
131+
121132 /**
122133 * Filter sensitive information
123134 */
@@ -223,6 +234,30 @@ export default class GrouperWorker extends Worker {
223234 }
224235 }
225236
237+ /**
238+ * Trims source code lines in event's backtrace to prevent memory leaks
239+ *
240+ * @param event - event to process
241+ */
242+ private trimSourceCodeLines ( event : EventDataAccepted < EventAddons > ) : void {
243+ if ( ! event . backtrace ) {
244+ return ;
245+ }
246+
247+ event . backtrace . forEach ( ( frame : BacktraceFrame ) => {
248+ if ( ! frame . sourceCode ) {
249+ return ;
250+ }
251+
252+ frame . sourceCode = frame . sourceCode . map ( ( line : SourceCodeLine ) => {
253+ return {
254+ line : line . line ,
255+ content : rightTrim ( line . content , MAX_CODE_LINE_LENGTH ) ,
256+ } ;
257+ } ) ;
258+ } ) ;
259+ }
260+
226261 /**
227262 * Get unique hash based on event type and title
228263 *
@@ -248,12 +283,18 @@ export default class GrouperWorker extends Worker {
248283
249284 const lastUniqueEvents = await this . findLastEvents ( projectId , eventsCountToCompare ) ;
250285
286+ /**
287+ * Trim titles to reduce CPU usage for Levenshtein comparison
288+ */
289+ const trimmedEventTitle = rightTrim ( event . title , MAX_CODE_LINE_LENGTH ) ;
290+
251291 /**
252292 * First try to find by Levenshtein distance
253293 */
254294 const similarByLevenshtein = lastUniqueEvents . filter ( prevEvent => {
255- const distance = levenshtein ( event . title , prevEvent . payload . title ) ;
256- const threshold = event . title . length * diffTreshold ;
295+ const trimmedPrevTitle = rightTrim ( prevEvent . payload . title , MAX_CODE_LINE_LENGTH ) ;
296+ const distance = levenshtein ( trimmedEventTitle , trimmedPrevTitle ) ;
297+ const threshold = trimmedEventTitle . length * diffTreshold ;
257298
258299 return distance < threshold ;
259300 } ) . pop ( ) ;
0 commit comments