@@ -22,9 +22,8 @@ export interface AuditBatchDependencies {
2222 scrapeAudit : ( auditId : string , tabId : number ) => Promise < CachedAuditData > ;
2323 saveAudit : ( auditId : string , audit : CachedAuditData ) => Promise < void > ;
2424 broadcast : ( state : "started" | "complete" ) => Promise < void > ;
25- delay ?: ( milliseconds : number ) => Promise < void > ;
2625 scrapeTimeoutMs ?: number ;
27- requestDelayMs ?: number ;
26+ concurrency ?: number ;
2827}
2928
3029export class AuditBatchController {
@@ -59,8 +58,17 @@ export class AuditBatchController {
5958 const result : AuditBatchResult = { succeeded : [ ] , failed : [ ] } ;
6059 await this . dependencies . broadcast ( "started" ) ;
6160
62- try {
63- for ( const [ index , auditId ] of auditIds . entries ( ) ) {
61+ // A few plain page fetches in flight at once — fewer than a normal page
62+ // load opens against one host — keeps the "Syncing" window short.
63+ const queue = [ ...auditIds ] ;
64+ let aborted = false ;
65+
66+ const worker = async ( ) : Promise < void > => {
67+ for (
68+ let auditId = queue . shift ( ) ;
69+ auditId !== undefined && ! aborted ;
70+ auditId = queue . shift ( )
71+ ) {
6472 try {
6573 const audit = await this . scrapeWithTimeout ( auditId , tabId ) ;
6674 await this . dependencies . saveAudit ( auditId , audit ) ;
@@ -71,20 +79,25 @@ export class AuditBatchController {
7179 // A dead session fails every remaining audit the same way; stop
7280 // instead of hammering the login redirect.
7381 if ( error instanceof Error && error . message === "AUTH_REQUIRED" ) {
74- result . failed . push ( ...auditIds . slice ( index + 1 ) ) ;
75- break ;
76- }
77- }
78-
79- if ( index < auditIds . length - 1 ) {
80- const delayMs = this . dependencies . requestDelayMs ?? 150 ;
81- if ( this . dependencies . delay ) {
82- await this . dependencies . delay ( delayMs ) ;
83- } else {
84- await new Promise ( ( resolve ) => setTimeout ( resolve , delayMs ) ) ;
82+ aborted = true ;
83+ result . failed . push ( ...queue . splice ( 0 ) ) ;
8584 }
8685 }
8786 }
87+ } ;
88+
89+ try {
90+ await Promise . all (
91+ Array . from (
92+ {
93+ length : Math . min (
94+ this . dependencies . concurrency ?? 3 ,
95+ auditIds . length ,
96+ ) ,
97+ } ,
98+ ( ) => worker ( ) ,
99+ ) ,
100+ ) ;
88101 } finally {
89102 await this . dependencies . broadcast ( "complete" ) ;
90103 const summary = `Audit batch complete: ${ result . succeeded . length } succeeded, ${ result . failed . length } failed` ;
0 commit comments