@@ -6,6 +6,10 @@ interface LoggerLike {
66}
77
88const ROUND_PRECISION = 100 ;
9+
10+ /**
11+ * Number of bytes in one mebibyte.
12+ */
913// eslint-disable-next-line @typescript-eslint/no-magic-numbers
1014const BYTES_IN_MEBIBYTE = 1024 * 1024 ;
1115
@@ -15,7 +19,15 @@ const BYTES_IN_MEBIBYTE = 1024 * 1024;
1519export default class GrouperMemoryMonitor {
1620 private readonly logger : LoggerLike ;
1721 private readonly config : GrouperMemoryConfig ;
22+
23+ /**
24+ * Task number of the last sustained-growth checkpoint.
25+ */
1826 private memoryCheckpointTask = 0 ;
27+
28+ /**
29+ * Heap usage (bytes) saved at the last sustained-growth checkpoint.
30+ */
1931 private memoryCheckpointHeapUsed = 0 ;
2032
2133 /**
@@ -54,11 +66,12 @@ export default class GrouperMemoryMonitor {
5466 *
5567 * @param handledTasksCount - currently handled tasks count.
5668 * @param title - event title if available.
69+ * @param projectId - project identifier.
5770 */
58- public logHandleError ( handledTasksCount : number , title : string | undefined ) : void {
71+ public logHandleError ( handledTasksCount : number , title : string | undefined , projectId : string ) : void {
5972 const suffix = title ? `title="${ title } "` : '' ;
6073
61- this . logCheckpoint ( 'handle-error' , process . memoryUsage ( ) , handledTasksCount , suffix ) ;
74+ this . logCheckpoint ( 'handle-error' , process . memoryUsage ( ) , handledTasksCount , projectId , suffix ) ;
6275 }
6376
6477 /**
@@ -67,17 +80,18 @@ export default class GrouperMemoryMonitor {
6780 * @param memoryUsage - process memory usage.
6881 * @param handledTasksCount - currently handled tasks count.
6982 * @param payloadSizeBytes - task payload size.
83+ * @param projectId - project identifier.
7084 */
71- public logBeforeHandle ( memoryUsage : NodeJS . MemoryUsage , handledTasksCount : number , payloadSizeBytes : number ) : void {
85+ public logBeforeHandle ( memoryUsage : NodeJS . MemoryUsage , handledTasksCount : number , payloadSizeBytes : number , projectId : string ) : void {
7286 if ( handledTasksCount !== 1 && handledTasksCount % this . config . logEveryTasks !== 0 ) {
7387 return ;
7488 }
7589
76- this . logCheckpoint ( 'before-handle' , memoryUsage , handledTasksCount , `payloadSize=${ payloadSizeBytes } b` ) ;
90+ this . logCheckpoint ( 'before-handle' , memoryUsage , handledTasksCount , projectId , `payloadSize=${ payloadSizeBytes } b` ) ;
7791 }
7892
7993 /**
80- * Log handle() completion memory details and growth checks .
94+ * Log post- handle memory stats and emit warnings on suspicious growth .
8195 *
8296 * @param memoryBeforeHandle - memory usage before handling.
8397 * @param handledTasksCount - currently handled tasks count.
@@ -97,25 +111,26 @@ export default class GrouperMemoryMonitor {
97111 const heapDeltaMb = Math . round ( ( heapDeltaBytes / BYTES_IN_MEBIBYTE ) * ROUND_PRECISION ) / ROUND_PRECISION ;
98112
99113 this . logger . info (
100- `[handle] done, ${ this . formatMemoryUsage ( memoryAfterHandle ) } heapDelta=${ heapDeltaMb } MB handled=${ handledTasksCount } `
114+ `[memory][project= ${ projectId } ] [ handle] done, ${ this . formatMemoryUsage ( memoryAfterHandle ) } heapDelta=${ heapDeltaMb } MB handled=${ handledTasksCount } `
101115 ) ;
102116
103117 if ( heapDeltaBytes > this . config . handleGrowthWarnMb * BYTES_IN_MEBIBYTE ) {
104118 this . logger . warn (
105- `[memory] high heap growth in single handle: heapDelta=${ heapDeltaMb } MB payloadSize=${ payloadSizeBytes } b title="${ title } " project= ${ projectId } `
119+ `[memory][project= ${ projectId } ] high heap growth in single handle: heapDelta=${ heapDeltaMb } MB payloadSize=${ payloadSizeBytes } b title="${ title } "`
106120 ) ;
107121 }
108122
109- this . checkMemoryGrowthWindow ( memoryAfterHandle , handledTasksCount ) ;
123+ this . checkMemoryGrowthWindow ( memoryAfterHandle , handledTasksCount , projectId ) ;
110124 }
111125
112126 /**
113127 * Logs sustained heap growth over a configurable number of handled tasks.
114128 *
115129 * @param memoryUsage - current process memory usage.
116130 * @param handledTasksCount - currently handled tasks count.
131+ * @param projectId - project identifier.
117132 */
118- private checkMemoryGrowthWindow ( memoryUsage : NodeJS . MemoryUsage , handledTasksCount : number ) : void {
133+ private checkMemoryGrowthWindow ( memoryUsage : NodeJS . MemoryUsage , handledTasksCount : number , projectId : string ) : void {
119134 const tasksInWindow = handledTasksCount - this . memoryCheckpointTask ;
120135
121136 if ( tasksInWindow < this . config . growthWindowTasks ) {
@@ -127,12 +142,12 @@ export default class GrouperMemoryMonitor {
127142 const heapUsedNowMb = Math . round ( ( memoryUsage . heapUsed / BYTES_IN_MEBIBYTE ) * ROUND_PRECISION ) / ROUND_PRECISION ;
128143
129144 this . logger . info (
130- `[memory] growth window tasks=${ tasksInWindow } handled=${ this . memoryCheckpointTask + 1 } -${ handledTasksCount } heapGrowth=${ heapGrowthMb } MB heapUsedNow=${ heapUsedNowMb } MB`
145+ `[memory][project= ${ projectId } ] growth window tasks=${ tasksInWindow } handled=${ this . memoryCheckpointTask + 1 } -${ handledTasksCount } heapGrowth=${ heapGrowthMb } MB heapUsedNow=${ heapUsedNowMb } MB`
131146 ) ;
132147
133148 if ( heapGrowthBytes > this . config . growthWarnMb * BYTES_IN_MEBIBYTE ) {
134149 this . logger . warn (
135- `[memory] possible leak detected: heap grew by ${ heapGrowthMb } MB in ${ tasksInWindow } handled tasks`
150+ `[memory][project= ${ projectId } ] possible leak detected: heap grew by ${ heapGrowthMb } MB in ${ tasksInWindow } handled tasks`
136151 ) ;
137152 }
138153
@@ -161,11 +176,13 @@ export default class GrouperMemoryMonitor {
161176 * @param stage - lifecycle stage.
162177 * @param memoryUsage - current process memory usage.
163178 * @param handledTasksCount - currently handled tasks count.
179+ * @param projectId - optional project identifier.
164180 * @param suffix - optional extra suffix.
165181 */
166- private logCheckpoint ( stage : string , memoryUsage : NodeJS . MemoryUsage , handledTasksCount : number , suffix = '' ) : void {
182+ private logCheckpoint ( stage : string , memoryUsage : NodeJS . MemoryUsage , handledTasksCount : number , projectId ?: string , suffix = '' ) : void {
167183 const extra = suffix ? ` ${ suffix } ` : '' ;
184+ const prefix = projectId ? `[memory][project=${ projectId } ]` : '[memory]' ;
168185
169- this . logger . info ( `[memory] stage=${ stage } handled=${ handledTasksCount } ${ this . formatMemoryUsage ( memoryUsage ) } ${ extra } ` ) ;
186+ this . logger . info ( `${ prefix } stage=${ stage } handled=${ handledTasksCount } ${ this . formatMemoryUsage ( memoryUsage ) } ${ extra } ` ) ;
170187 }
171188}
0 commit comments