diff --git a/package.json b/package.json index 07de275..c5476b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "durable-apis", - "version": "0.0.9", + "version": "0.0.10", "description": "Functional-style Cloudflare Durable Objects with direct API calls from Cloudflare Workers and TypeScript support.", "main": "dist/durable-apis.js", "types": "dist/durable-apis.d.ts", diff --git a/src/durable-apis.ts b/src/durable-apis.ts index a6f23fc..f59bf6d 100644 --- a/src/durable-apis.ts +++ b/src/durable-apis.ts @@ -8,6 +8,7 @@ import { export type EmptyObj = {[key: string]: any}; const URL = 'https://durable/'; +const maxRetries = 10; export type Object = Record; export type DurableInitConstructor = {new (state: DurableObjectState, env: Env): T}; @@ -137,8 +138,14 @@ function extendNamespace(namespace: DurableObjectNamespace) { return namespace; } -async function stubFetch(obj: DurableObjectStub, prop: string, content: any) { - return obj.fetch(createRequest(prop, content)).then(transformResponse) +async function stubFetch(obj: DurableObjectStub, prop: string, content: any, retries = 0) { + return obj.fetch(createRequest(prop, content)).then(transformResponse).catch(err => { + if (!shouldRetry(err, retries)) return Promise.reject(err); + // Retry up to 11 times over 30 seconds with exponential backoff. 20ms, 40ms, etc + return new Promise(resolve => setTimeout(resolve, Math.pow(2, retries) * 10)).then(() => { + return stubFetch(obj, prop, content, retries + 1); + }); + }); } function createRequest(prop: string, content: any) { @@ -169,3 +176,11 @@ async function transformResponse(response: Response) { } catch (err) {} return response; } + +function shouldRetry(err: any, retries: number) { + if (retries > maxRetries) return false; + err = err + ''; + if (err.includes('Network connection lost.')) return true; + if (err.includes('Cannot resolve Durable Object due to transient issue on remote node.')) return true; + return false; +}