@@ -11,9 +11,12 @@ import yargs from "yargs";
11
11
import { hideBin } from "yargs/helpers" ;
12
12
import { z } from "zod" ;
13
13
14
+ const DEFAULT_RETRIES = 3 ;
15
+
14
16
type LoadedConfig = {
15
17
contract : EvmEntropyContract ;
16
18
interval : number ;
19
+ retries : number ;
17
20
} ;
18
21
19
22
function timeToSeconds ( timeStr : string ) : number {
@@ -46,6 +49,7 @@ async function loadConfig(configPath: string): Promise<LoadedConfig[]> {
46
49
"chain-id" : z . string ( ) ,
47
50
interval : z . string ( ) ,
48
51
"rpc-endpoint" : z . string ( ) . optional ( ) ,
52
+ retries : z . number ( ) . default ( DEFAULT_RETRIES ) ,
49
53
} ) ,
50
54
) ;
51
55
const configContent = ( await import ( configPath , {
@@ -78,7 +82,7 @@ async function loadConfig(configPath: string): Promise<LoadedConfig[]> {
78
82
evmChain . networkId ,
79
83
) ;
80
84
}
81
- return { contract : firstContract , interval } ;
85
+ return { contract : firstContract , interval, retries : config . retries } ;
82
86
} ) ;
83
87
return loadedConfigs ;
84
88
}
@@ -188,31 +192,63 @@ export const main = function () {
188
192
privateKeyFileContent . replace ( "0x" , "" ) . trimEnd ( ) ,
189
193
) ;
190
194
logger . info ( "Running" ) ;
191
- const promises = configs . map ( async ( { contract, interval } ) => {
192
- const child = logger . child ( { chain : contract . chain . getId ( ) } ) ;
193
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
194
- while ( true ) {
195
- try {
196
- await Promise . race ( [
197
- testLatency ( contract , privateKey , child ) ,
198
- new Promise ( ( _ , reject ) =>
199
- setTimeout ( ( ) => {
200
- reject (
201
- new Error (
202
- "Timeout: 120s passed but testLatency function was not resolved" ,
203
- ) ,
195
+ const promises = configs . map (
196
+ async ( { contract, interval, retries } ) => {
197
+ const child = logger . child ( { chain : contract . chain . getId ( ) } ) ;
198
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
199
+ while ( true ) {
200
+ let lastError : Error | undefined ;
201
+ let success = false ;
202
+
203
+ for ( let attempt = 1 ; attempt <= retries ; attempt ++ ) {
204
+ try {
205
+ await Promise . race ( [
206
+ testLatency ( contract , privateKey , child ) ,
207
+ new Promise ( ( _ , reject ) =>
208
+ setTimeout ( ( ) => {
209
+ reject (
210
+ new Error (
211
+ "Timeout: 120s passed but testLatency function was not resolved" ,
212
+ ) ,
213
+ ) ;
214
+ } , 120_000 ) ,
215
+ ) ,
216
+ ] ) ;
217
+ success = true ;
218
+ break ;
219
+ } catch ( error ) {
220
+ lastError = error as Error ;
221
+ child . warn (
222
+ { attempt, maxRetries : retries , error : error } ,
223
+ `Attempt ${ attempt . toString ( ) } /${ retries . toString ( ) } failed, ${ attempt < retries ? "retrying..." : "all retries exhausted" } ` ,
224
+ ) ;
225
+
226
+ if ( attempt < retries ) {
227
+ // Wait a bit before retrying (exponential backoff, max 10s)
228
+ const backoffDelay = Math . min (
229
+ 2000 * Math . pow ( 2 , attempt - 1 ) ,
230
+ 10_000 ,
231
+ ) ;
232
+ await new Promise ( ( resolve ) =>
233
+ setTimeout ( resolve , backoffDelay ) ,
204
234
) ;
205
- } , 120_000 ) ,
206
- ) ,
207
- ] ) ;
208
- } catch ( error ) {
209
- child . error ( error , "Error testing latency" ) ;
235
+ }
236
+ }
237
+ }
238
+
239
+ if ( ! success && lastError ) {
240
+ child . error (
241
+ { error : lastError , retriesExhausted : retries } ,
242
+ "All retries exhausted, callback was not called." ,
243
+ ) ;
244
+ }
245
+
246
+ await new Promise ( ( resolve ) =>
247
+ setTimeout ( resolve , interval * 1000 ) ,
248
+ ) ;
210
249
}
211
- await new Promise ( ( resolve ) =>
212
- setTimeout ( resolve , interval * 1000 ) ,
213
- ) ;
214
- }
215
- } ) ;
250
+ } ,
251
+ ) ;
216
252
await Promise . all ( promises ) ;
217
253
} ,
218
254
)
0 commit comments