@@ -85,6 +85,7 @@ public class OptOutSqsLogProducer extends AbstractVerticle {
8585 private final int visibilityTimeout ;
8686 private final int deltaWindowSeconds ; // Time window for each delta file (5 minutes = 300 seconds)
8787 private final int jobTimeoutSeconds ;
88+ private final int maxMessagesPerFile ; // Memory protection: max messages per delta file
8889 private final int listenPort ;
8990 private final String internalApiKey ;
9091 private final InternalAuthMiddleware internalAuth ;
@@ -138,6 +139,7 @@ public OptOutSqsLogProducer(JsonObject jsonConfig, ICloudStorage cloudStorage, O
138139 this .visibilityTimeout = jsonConfig .getInteger (Const .Config .OptOutSqsVisibilityTimeoutProp , 240 ); // 4 minutes default
139140 this .deltaWindowSeconds = 300 ; // Fixed 5 minutes for all deltas
140141 this .jobTimeoutSeconds = jsonConfig .getInteger (Const .Config .OptOutDeltaJobTimeoutSecondsProp , 10800 ); // 3 hours default
142+ this .maxMessagesPerFile = jsonConfig .getInteger (Const .Config .OptOutMaxMessagesPerFileProp , 10000 ); // Memory protection limit
141143
142144 // HTTP server configuration - use port offset + 1 to avoid conflicts
143145 this .listenPort = Const .Port .ServicePortForOptOut + Utils .getPortOffset () + 1 ;
@@ -149,11 +151,12 @@ public OptOutSqsLogProducer(JsonObject jsonConfig, ICloudStorage cloudStorage, O
149151 int bufferSize = jsonConfig .getInteger (Const .Config .OptOutProducerBufferSizeProp );
150152 this .buffer = ByteBuffer .allocate (bufferSize ).order (ByteOrder .LITTLE_ENDIAN );
151153
152- // Initialize window reader
154+ // Initialize window reader with memory protection limit
153155 this .windowReader = new SqsWindowReader (
154156 this .sqsClient , this .queueUrl , this .maxMessagesPerPoll ,
155- this .visibilityTimeout , this .deltaWindowSeconds
157+ this .visibilityTimeout , this .deltaWindowSeconds , this . maxMessagesPerFile
156158 );
159+ LOGGER .info ("OptOutSqsLogProducer initialized with maxMessagesPerFile: {}" , this .maxMessagesPerFile );
157160 }
158161
159162 @ Override
@@ -344,7 +347,7 @@ private JsonObject produceDeltasBlocking() throws Exception {
344347 DeltaProductionResult deltaResult = this .produceBatchedDeltas ();
345348
346349 // Determine status based on results
347- if (deltaResult .getDeltasProduced () == 0 && deltaResult .stoppedDueToRecentMessages ()) {
350+ if (deltaResult .getDeltasProduced () == 0 && deltaResult .stoppedDueToMessagesTooRecent ()) {
348351 // No deltas produced because all messages were too recent
349352 result .put ("status" , "skipped" );
350353 result .put ("reason" , "All messages too recent" );
@@ -365,30 +368,31 @@ private JsonObject produceDeltasBlocking() throws Exception {
365368 /**
366369 * Reads messages from SQS and produces delta files in 5 minute batches.
367370 * Continues until queue is empty or messages are too recent.
371+ * Windows are limited to maxMessagesPerFile for memory protection.
368372 *
369373 * @return DeltaProductionResult with counts and stop reason
370374 * @throws IOException if delta production fails
371375 */
372376 private DeltaProductionResult produceBatchedDeltas () throws IOException {
373377 int deltasProduced = 0 ;
374378 int totalEntriesProcessed = 0 ;
375- boolean stoppedDueToRecentMessages = false ;
379+ boolean stoppedDueToMessagesTooRecent = false ;
376380
377381 long jobStartTime = OptOutUtils .nowEpochSeconds ();
378- LOGGER .info ("Starting delta production from SQS queue" );
382+ LOGGER .info ("Starting delta production from SQS queue (maxMessagesPerFile: {})" , this . maxMessagesPerFile );
379383
380384 // Read and process windows until done
381385 while (true ) {
382386 if (checkJobTimeout (jobStartTime )){
383387 break ;
384388 }
385389
386- // Read one complete 5-minute window
390+ // Read one complete 5-minute window (limited to maxMessagesPerFile)
387391 SqsWindowReader .WindowReadResult windowResult = windowReader .readWindow ();
388392
389393 // If no messages, we're done (queue empty or messages too recent)
390394 if (windowResult .isEmpty ()) {
391- stoppedDueToRecentMessages = windowResult .stoppedDueToRecentMessages ();
395+ stoppedDueToMessagesTooRecent = windowResult .stoppedDueToMessagesTooRecent ();
392396 LOGGER .info ("Delta production complete - no more eligible messages" );
393397 break ;
394398 }
@@ -422,7 +426,7 @@ private DeltaProductionResult produceBatchedDeltas() throws IOException {
422426 LOGGER .info ("Delta production complete: took {}s, produced {} deltas, processed {} entries" ,
423427 totalDuration , deltasProduced , totalEntriesProcessed );
424428
425- return new DeltaProductionResult (deltasProduced , totalEntriesProcessed , stoppedDueToRecentMessages );
429+ return new DeltaProductionResult (deltasProduced , totalEntriesProcessed , stoppedDueToMessagesTooRecent );
426430 }
427431
428432 /**
0 commit comments