diff --git a/src/services/RedstoneServiceV3.ts b/src/services/RedstoneServiceV3.ts index 1e1a6e5..4031467 100644 --- a/src/services/RedstoneServiceV3.ts +++ b/src/services/RedstoneServiceV3.ts @@ -27,7 +27,7 @@ import type { } from "../data/index.js"; import { DI } from "../di.js"; import { type ILogger, Logger } from "../log/index.js"; -import { formatTs } from "../utils/index.js"; +import { formatTs, retry } from "../utils/index.js"; import type { AddressProviderService } from "./AddressProviderService.js"; import type Client from "./Client.js"; import type { PriceOnDemandExtras, PriceUpdate } from "./liquidate/index.js"; @@ -364,7 +364,12 @@ export class RedstoneServiceV3 { historicalTimestamp: this.#optimisticTimestamp, }); wrapper.setMetadataTimestamp(Date.now()); - const dataPayload = await wrapper.prepareRedstonePayload(true); + // redstone does not provide any error types, just string messages + // so just retry all redstone errors + const dataPayload = await retry( + () => wrapper.prepareRedstonePayload(true), + { attempts: 2 }, + ); // unsigned metadata looks like // "1724772413180#0.6.1#redstone-primary-prod___" diff --git a/src/utils/index.ts b/src/utils/index.ts index d972d60..89a7e5f 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -2,5 +2,6 @@ export * from "./bigint-serializer.js"; export * from "./detect-network.js"; export * from "./etherscan.js"; export * from "./formatters.js"; +export * from "./retry.js"; export * from "./types.js"; export * from "./typescript.js"; diff --git a/src/utils/retry.ts b/src/utils/retry.ts new file mode 100644 index 0000000..74c64aa --- /dev/null +++ b/src/utils/retry.ts @@ -0,0 +1,24 @@ +import { setTimeout } from "node:timers/promises"; + +export interface RetryOptions { + attempts?: number; + interval?: number; +} + +export async function retry( + fn: () => Promise, + options: RetryOptions = {}, +): Promise { + const { attempts = 3, interval = 200 } = options; + let err: any; + for (let i = 0; i < attempts; i++) { + try { + const result = await fn(); + return result; + } catch (e) { + err = e; + await setTimeout(interval); + } + } + throw err ?? new Error("all attempts failed"); +}