@@ -66,6 +66,23 @@ function sleep(ms: number): Promise<void> {
6666 } ) ;
6767}
6868
69+ async function mapConcurrent < T , R > ( items : T [ ] , limit : number , fn : ( item : T ) => Promise < R > ) : Promise < R [ ] > {
70+ const results : R [ ] = new Array ( items . length ) ;
71+ let currentIndex = 0 ;
72+ const worker = async ( ) => {
73+ while ( currentIndex < items . length ) {
74+ const index = currentIndex ++ ;
75+ results [ index ] = await fn ( items [ index ] ) ;
76+ }
77+ } ;
78+ const workers = [ ] ;
79+ for ( let i = 0 ; i < Math . min ( limit , items . length ) ; i ++ ) {
80+ workers . push ( worker ( ) ) ;
81+ }
82+ await Promise . all ( workers ) ;
83+ return results ;
84+ }
85+
6986export class DefaultChecker {
7087 private contractId : string ;
7188 private termLedgers : number ;
@@ -74,6 +91,7 @@ export class DefaultChecker {
7491 private maxLoansPerRun : number ;
7592 private pollAttempts : number ;
7693 private pollSleepMs : number ;
94+ private concurrency : number ;
7795
7896 constructor ( ) {
7997 this . contractId = process . env . LOAN_MANAGER_CONTRACT_ID || "" ;
@@ -98,6 +116,10 @@ export class DefaultChecker {
98116 process . env . DEFAULT_CHECK_POLL_SLEEP_MS ,
99117 1_000 ,
100118 ) ;
119+ this . concurrency = parsePositiveInt (
120+ process . env . DEFAULT_CHECK_CONCURRENCY ,
121+ 3 ,
122+ ) ;
101123 }
102124
103125 private assertConfigured ( ) : {
@@ -456,16 +478,14 @@ export class DefaultChecker {
456478 targetLoanCount : targetIds . length ,
457479 } ) ;
458480
459- const batches : DefaultCheckBatchResult [ ] = [ ] ;
460- for ( const batch of chunk ( targetIds , this . batchSize ) ) {
461- if ( ! batch . length ) continue ;
481+ const allChunks = chunk ( targetIds , this . batchSize ) . filter ( b => b . length > 0 ) ;
482+ const batchResults = await mapConcurrent ( allChunks , this . concurrency , async ( batch ) => {
462483 const result = await this . submitCheckDefaultsWithTimeout (
463484 server ,
464485 signer ,
465486 passphrase ,
466487 batch ,
467488 ) ;
468- batches . push ( result ) ;
469489
470490 logger . info ( "default_check.batch" , {
471491 runId,
@@ -476,15 +496,17 @@ export class DefaultChecker {
476496 error : result . error ,
477497 timedOut : result . timedOut ,
478498 } ) ;
479- }
499+
500+ return result ;
501+ } ) ;
480502
481503 const loansChecked = targetIds . length ;
482- const successfulSubmissions = batches . filter ( ( b ) => ! b . error && ! b . timedOut ) . length ;
483- const failedSubmissions = batches . filter ( ( b ) => b . error !== undefined || b . timedOut === true ) . length ;
504+ const successfulSubmissions = batchResults . filter ( ( b ) => ! b . error && b . txHash ) . length ;
505+ const failedSubmissions = batchResults . filter ( ( b ) => b . error || ! b . txHash ) . length ;
484506
485507 logger . info ( "default_check.run.complete" , {
486508 runId,
487- batches : batches . length ,
509+ batches : batchResults . length ,
488510 loansChecked,
489511 successfulSubmissions,
490512 failedSubmissions,
@@ -508,7 +530,7 @@ export class DefaultChecker {
508530 ...( stats . ledgersPastOldestDue !== undefined
509531 ? { ledgersPastOldestDue : stats . ledgersPastOldestDue }
510532 : { } ) ,
511- batches,
533+ batches : batchResults ,
512534 } ;
513535 } finally {
514536 // Always release the lock, even if the run failed
0 commit comments