Ver código fonte

feat(entropy-tester): add retries (#2855)

Tejas Badadare 4 meses atrás
pai
commit
8e4049fd9e
2 arquivos alterados com 61 adições e 25 exclusões
  1. 1 1
      apps/entropy-tester/package.json
  2. 60 24
      apps/entropy-tester/src/index.ts

+ 1 - 1
apps/entropy-tester/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/entropy-tester",
-  "version": "1.1.0",
+  "version": "1.2.0",
   "description": "Utility to test entropy provider callbacks",
   "private": true,
   "type": "module",

+ 60 - 24
apps/entropy-tester/src/index.ts

@@ -11,9 +11,12 @@ import yargs from "yargs";
 import { hideBin } from "yargs/helpers";
 import { z } from "zod";
 
+const DEFAULT_RETRIES = 3;
+
 type LoadedConfig = {
   contract: EvmEntropyContract;
   interval: number;
+  retries: number;
 };
 
 function timeToSeconds(timeStr: string): number {
@@ -46,6 +49,7 @@ async function loadConfig(configPath: string): Promise<LoadedConfig[]> {
       "chain-id": z.string(),
       interval: z.string(),
       "rpc-endpoint": z.string().optional(),
+      retries: z.number().default(DEFAULT_RETRIES),
     }),
   );
   const configContent = (await import(configPath, {
@@ -78,7 +82,7 @@ async function loadConfig(configPath: string): Promise<LoadedConfig[]> {
         evmChain.networkId,
       );
     }
-    return { contract: firstContract, interval };
+    return { contract: firstContract, interval, retries: config.retries };
   });
   return loadedConfigs;
 }
@@ -188,31 +192,63 @@ export const main = function () {
           privateKeyFileContent.replace("0x", "").trimEnd(),
         );
         logger.info("Running");
-        const promises = configs.map(async ({ contract, interval }) => {
-          const child = logger.child({ chain: contract.chain.getId() });
-          // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
-          while (true) {
-            try {
-              await Promise.race([
-                testLatency(contract, privateKey, child),
-                new Promise((_, reject) =>
-                  setTimeout(() => {
-                    reject(
-                      new Error(
-                        "Timeout: 120s passed but testLatency function was not resolved",
-                      ),
+        const promises = configs.map(
+          async ({ contract, interval, retries }) => {
+            const child = logger.child({ chain: contract.chain.getId() });
+            // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+            while (true) {
+              let lastError: Error | undefined;
+              let success = false;
+
+              for (let attempt = 1; attempt <= retries; attempt++) {
+                try {
+                  await Promise.race([
+                    testLatency(contract, privateKey, child),
+                    new Promise((_, reject) =>
+                      setTimeout(() => {
+                        reject(
+                          new Error(
+                            "Timeout: 120s passed but testLatency function was not resolved",
+                          ),
+                        );
+                      }, 120_000),
+                    ),
+                  ]);
+                  success = true;
+                  break;
+                } catch (error) {
+                  lastError = error as Error;
+                  child.warn(
+                    { attempt, maxRetries: retries, error: error },
+                    `Attempt ${attempt.toString()}/${retries.toString()} failed, ${attempt < retries ? "retrying..." : "all retries exhausted"}`,
+                  );
+
+                  if (attempt < retries) {
+                    // Wait a bit before retrying (exponential backoff, max 10s)
+                    const backoffDelay = Math.min(
+                      2000 * Math.pow(2, attempt - 1),
+                      10_000,
+                    );
+                    await new Promise((resolve) =>
+                      setTimeout(resolve, backoffDelay),
                     );
-                  }, 120_000),
-                ),
-              ]);
-            } catch (error) {
-              child.error(error, "Error testing latency");
+                  }
+                }
+              }
+
+              if (!success && lastError) {
+                child.error(
+                  { error: lastError, retriesExhausted: retries },
+                  "All retries exhausted, callback was not called.",
+                );
+              }
+
+              await new Promise((resolve) =>
+                setTimeout(resolve, interval * 1000),
+              );
             }
-            await new Promise((resolve) =>
-              setTimeout(resolve, interval * 1000),
-            );
-          }
-        });
+          },
+        );
         await Promise.all(promises);
       },
     )