From c5788932f809b752da760fb55a06a640813c9629 Mon Sep 17 00:00:00 2001 From: Steven Yi Date: Fri, 14 Feb 2025 12:00:59 -0500 Subject: [PATCH] fix: modify retry logic to only occur on dryrun exceptions --- src/common/contracts/ao-process.ts | 116 ++++++++++++++++------------- src/types/common.ts | 14 ++++ 2 files changed, 80 insertions(+), 50 deletions(-) diff --git a/src/common/contracts/ao-process.ts b/src/common/contracts/ao-process.ts index eed31c44..d0026522 100644 --- a/src/common/contracts/ao-process.ts +++ b/src/common/contracts/ao-process.ts @@ -15,7 +15,12 @@ */ import { connect } from '@permaweb/aoconnect'; -import { AOContract, AoClient, AoSigner } from '../../types/index.js'; +import { + AOContract, + AoClient, + AoSigner, + DryRunResult, +} from '../../types/index.js'; import { getRandomText } from '../../utils/base64.js'; import { errorMessageFromOutput } from '../../utils/index.js'; import { safeDecode } from '../../utils/json.js'; @@ -60,56 +65,28 @@ export class AOProcess implements AOContract { retries?: number; fromAddress?: string; }): Promise { + this.logger.debug(`Evaluating read interaction on process`, { + tags, + processId: this.processId, + }); + // map tags to inputs + const dryRunInput = { + process: this.processId, + tags, + }; + if (fromAddress !== undefined) { + dryRunInput['Owner'] = fromAddress; + } + let attempts = 0; - let lastError: Error | undefined; + let result: DryRunResult | undefined = undefined; + while (attempts < retries) { try { - this.logger.debug(`Evaluating read interaction on process`, { - tags, - processId: this.processId, - }); - // map tags to inputs - const dryRunInput = { - process: this.processId, - tags, - }; - if (fromAddress !== undefined) { - dryRunInput['Owner'] = fromAddress; - } - const result = await this.ao.dryrun(dryRunInput); - this.logger.debug(`Read interaction result`, { - result, - processId: this.processId, - }); - - const error = errorMessageFromOutput(result); - if (error !== undefined) { - throw new Error(error); - } - - if (result.Messages === undefined || result.Messages.length === 0) { - this.logger.debug( - `Process ${this.processId} does not support provided action.`, - { - result, - tags, - processId: this.processId, - }, - ); - throw new Error( - `Process ${this.processId} does not support provided action.`, - ); - } - const messageData = result.Messages?.[0]?.Data; - - // return undefined if no data is returned - if (this.isMessageDataEmpty(messageData)) { - return undefined as K; - } - - const response: K = safeDecode(messageData); - return response; - } catch (error: any) { + result = await this.ao.dryrun(dryRunInput); + // break on successful return of result + break; + } catch (error) { attempts++; this.logger.debug(`Read attempt ${attempts} failed`, { error: error?.message, @@ -117,7 +94,10 @@ export class AOProcess implements AOContract { tags, processId: this.processId, }); - lastError = error; + + if (attempts === retries) { + throw error; + } // exponential backoff await new Promise((resolve) => @@ -125,7 +105,43 @@ export class AOProcess implements AOContract { ); } } - throw lastError; + + if (result === undefined) { + throw new Error('Unexpected error when evaluating read interaction'); + } + + this.logger.debug(`Read interaction result`, { + result, + processId: this.processId, + }); + + const error = errorMessageFromOutput(result); + if (error !== undefined) { + throw new Error(error); + } + + if (result.Messages === undefined || result.Messages.length === 0) { + this.logger.debug( + `Process ${this.processId} does not support provided action.`, + { + result, + tags, + processId: this.processId, + }, + ); + throw new Error( + `Process ${this.processId} does not support provided action.`, + ); + } + const messageData = result.Messages?.[0]?.Data; + + // return undefined if no data is returned + if (this.isMessageDataEmpty(messageData)) { + return undefined as K; + } + + const response: K = safeDecode(messageData); + return response; } async send({ diff --git a/src/types/common.ts b/src/types/common.ts index 4ee71836..f11443cb 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -141,3 +141,17 @@ export type AoWriteAction = ( params: P, options?: WriteOptions, ) => Promise; + +// the following are from @permaweb/aoconnect which does not export these types directly +export type DryRunResult = { + Output: any; + Messages: any[]; + Spawns: any[]; + Error?: any; +}; +export type MessageResult = { + Output: any; + Messages: any[]; + Spawns: any[]; + Error?: any; +};