88 * It handles timeout issues by processing wallets in small batches.
99 *
1010 * Usage:
11- * node scripts/batch-snapshot-orchestrator.js
12- * SNAPSHOT_AUTH_TOKEN=your_token node scripts/batch-snapshot-orchestrator.js
11+ * npx tsx scripts/batch-snapshot-orchestrator.ts
12+ * SNAPSHOT_AUTH_TOKEN=your_token npx tsx scripts/batch-snapshot-orchestrator.ts
1313 *
1414 * Environment Variables:
1515 * - API_BASE_URL: Base URL for the API (default: http://localhost:3000)
1919 * - MAX_RETRIES: Maximum retries for failed batches (default: 3)
2020 */
2121
22+ interface BatchProgress {
23+ processedInBatch: number ;
24+ walletsInBatch: number ;
25+ failedInBatch: number ;
26+ snapshotsStored: number ;
27+ totalAdaBalance: number ;
28+ totalBatches: number ;
29+ }
30+
31+ interface BatchResponse {
32+ success: boolean ;
33+ message ? : string ;
34+ progress: BatchProgress ;
35+ }
36+
37+ interface BatchResults {
38+ totalBatches: number ;
39+ completedBatches: number ;
40+ failedBatches: number ;
41+ totalWalletsProcessed: number ;
42+ totalWalletsFailed: number ;
43+ totalAdaBalance: number ;
44+ totalSnapshotsStored: number ;
45+ executionTime: number ;
46+ }
47+
48+ interface BatchConfig {
49+ apiBaseUrl: string ;
50+ authToken: string ;
51+ batchSize: number ;
52+ delayBetweenBatches: number ;
53+ maxRetries: number ;
54+ }
55+
56+ interface ApiResponse < T > {
57+ data : T ;
58+ status: number ;
59+ }
60+
2261class BatchSnapshotOrchestrator {
62+ private config : BatchConfig ;
63+ private results : BatchResults ;
64+
2365 constructor ( ) {
2466 this . config = this . loadConfig ( ) ;
2567 this . results = {
@@ -34,7 +76,7 @@ class BatchSnapshotOrchestrator {
3476 } ;
3577 }
3678
37- loadConfig ( ) {
79+ private loadConfig ( ) : BatchConfig {
3880 const apiBaseUrl = process . env . API_BASE_URL || 'http://localhost:3000' ;
3981 const authToken = process . env . SNAPSHOT_AUTH_TOKEN ;
4082
@@ -51,48 +93,55 @@ class BatchSnapshotOrchestrator {
5193 } ;
5294 }
5395
54- async makeRequest ( /** @type { string } */ url , /** @type { RequestInit } */ options = { } ) {
96+ private async makeRequest < T > ( url : string , options : RequestInit = { } ) : Promise < ApiResponse < T >> {
5597 try {
98+ // Add timeout to prevent hanging requests
99+ const controller = new AbortController ( ) ;
100+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 30000 ) ; // 30 second timeout
101+
56102 const response = await fetch ( url , {
57103 ...options ,
104+ signal : controller . signal ,
58105 headers : {
59106 'Authorization' : `Bearer ${ this . config . authToken } ` ,
60107 'Content-Type' : 'application/json' ,
61108 ...( options . headers || { } ) ,
62109 } ,
63110 } ) ;
111+
112+ clearTimeout ( timeoutId ) ;
64113
65114 if ( ! response . ok ) {
66115 throw new Error ( `HTTP ${ response . status } : ${ response . statusText } ` ) ;
67116 }
68117
69- const data = await response . json ( ) ;
118+ const data = await response . json ( ) as T ;
70119 return { data, status : response . status } ;
71120 } catch ( error ) {
121+ if ( error instanceof Error && error . name === 'AbortError' ) {
122+ throw new Error ( 'Request timeout after 30 seconds' ) ;
123+ }
72124 throw error ;
73125 }
74126 }
75127
76- async delay ( /** @type { number } */ seconds ) {
128+ private async delay ( seconds : number ) : Promise < void > {
77129 return new Promise ( resolve => setTimeout ( resolve , seconds * 1000 ) ) ;
78130 }
79131
80- async processBatch ( /** @type { number } */ batchNumber , /** @type { string } */ batchId ) {
132+ private async processBatch ( batchNumber : number , batchId : string ) : Promise < BatchProgress | null > {
81133 console . log ( `📦 Processing batch ${ batchNumber } ...` ) ;
82134
83135 for ( let attempt = 1 ; attempt <= this . config . maxRetries ; attempt ++ ) {
84136 try {
85- const { data } = await this . makeRequest (
86- `${ this . config . apiBaseUrl } /api/v1/stats/run-snapshots-batch` ,
87- {
88- method : 'POST' ,
89- body : JSON . stringify ( {
90- batchId,
91- batchNumber,
92- batchSize : this . config . batchSize ,
93- } ) ,
94- }
95- ) ;
137+ const url = new URL ( `${ this . config . apiBaseUrl } /api/v1/stats/run-snapshots-batch` ) ;
138+ url . searchParams . set ( 'batchId' , batchId ) ;
139+ url . searchParams . set ( 'batchNumber' , batchNumber . toString ( ) ) ;
140+ url . searchParams . set ( 'batchSize' , this . config . batchSize . toString ( ) ) ;
141+
142+ const { data } = await this . makeRequest < BatchResponse > ( url . toString ( ) , {
143+ method : 'POST' ,
144+ } ) ;
96145
97146 if ( data . success ) {
98147 console . log ( `✅ Batch ${ batchNumber } completed successfully` ) ;
@@ -124,7 +173,7 @@ class BatchSnapshotOrchestrator {
124173 return null ;
125174 }
126175
127- async run ( ) {
176+ public async run ( ) : Promise < BatchResults > {
128177 const startTime = Date . now ( ) ;
129178 const batchId = `snapshot-${ Date . now ( ) } ` ;
130179
@@ -152,10 +201,8 @@ class BatchSnapshotOrchestrator {
152201 // Process remaining batches
153202 for ( let batchNumber = 2 ; batchNumber <= this . results . totalBatches ; batchNumber ++ ) {
154203 // Delay between batches to prevent overwhelming the server
155- if ( batchNumber > 2 ) {
156- console . log ( `⏳ Waiting ${ this . config . delayBetweenBatches } s before next batch...` ) ;
157- await this . delay ( this . config . delayBetweenBatches ) ;
158- }
204+ console . log ( `⏳ Waiting ${ this . config . delayBetweenBatches } s before next batch...` ) ;
205+ await this . delay ( this . config . delayBetweenBatches ) ;
159206
160207 const batchProgress = await this . processBatch ( batchNumber , batchId ) ;
161208
@@ -204,7 +251,7 @@ class BatchSnapshotOrchestrator {
204251}
205252
206253// Main execution
207- async function main ( ) {
254+ async function main ( ) : Promise < void > {
208255 try {
209256 const orchestrator = new BatchSnapshotOrchestrator ( ) ;
210257 await orchestrator . run ( ) ;
@@ -217,7 +264,7 @@ async function main() {
217264}
218265
219266// Export for use in other modules
220- export { BatchSnapshotOrchestrator } ;
267+ export { BatchSnapshotOrchestrator , type BatchResults , type BatchProgress , type BatchConfig } ;
221268
222269// Run if this file is executed directly
223270if ( import . meta. url === `file://${ process . argv [ 1 ] } ` ) {
0 commit comments