From 5bfb042646c333bc67309a980af9c647bc4cff04 Mon Sep 17 00:00:00 2001 From: anonpenguin23 Date: Wed, 5 Nov 2025 17:30:58 +0200 Subject: [PATCH] Implement retry logic for content retrieval in StorageClient - Added retry mechanism for the `get` method to handle eventual consistency in IPFS Cluster. - Introduced exponential backoff strategy for retries, allowing up to 8 attempts with increasing wait times. - Enhanced error handling to differentiate between 404 errors and other failures, ensuring robust content retrieval. --- src/storage/client.ts | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/storage/client.ts b/src/storage/client.ts index e69df8f..f1b36c9 100644 --- a/src/storage/client.ts +++ b/src/storage/client.ts @@ -150,13 +150,46 @@ export class StorageClient { * ``` */ async get(cid: string): Promise> { - const response = await this.httpClient.getBinary(`/v1/storage/get/${cid}`); + // Retry logic for content retrieval - content may not be immediately available + // after upload due to eventual consistency in IPFS Cluster + // IPFS Cluster pins can take 2-3+ seconds to complete across all nodes + const maxAttempts = 8; + let lastError: Error | null = null; - if (!response.body) { - throw new Error("Response body is null"); + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + try { + const response = await this.httpClient.getBinary( + `/v1/storage/get/${cid}` + ); + + if (!response.body) { + throw new Error("Response body is null"); + } + + return response.body; + } catch (error: any) { + lastError = error; + + // Check if this is a 404 error (content not found) + const isNotFound = + error?.httpStatus === 404 || + error?.message?.includes("not found") || + error?.message?.includes("404"); + + // If it's not a 404 error, or this is the last attempt, give up + if (!isNotFound || attempt === maxAttempts) { + throw error; + } + + // Wait before retrying (exponential backoff: 400ms, 800ms, 1200ms, etc.) + // This gives up to ~12 seconds total wait time, covering typical pin completion + const backoffMs = attempt * 2500; + await new Promise((resolve) => setTimeout(resolve, backoffMs)); + } } - return response.body; + // This should never be reached, but TypeScript needs it + throw lastError || new Error("Failed to retrieve content"); } /**