MCPcopy Create free account
hub / github.com/Mnexa-AI/e2a / RetryHttpLibrary

Class RetryHttpLibrary

sdks/typescript/src/v1/retry.ts:54–235  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

52}
53
54export class RetryHttpLibrary implements HttpLibrary {
55 constructor(
56 private readonly inner: HttpLibrary,
57 private readonly opts: RetryOptions = {},
58 ) {}
59
60 send(request: RequestContext): Observable<ResponseContext> {
61 return from(this.sendWithRetry(request));
62 }
63
64 private async sendWithRetry(request: RequestContext): Promise<ResponseContext> {
65 // Decide retry-safety BEFORE mutating headers — it depends on whether the
66 // generated layer already emitted an Idempotency-Key stub (server-deduped
67 // POSTs) which ensureIdempotencyKey would otherwise fill in and obscure.
68 const retrySafe = this.isRetrySafe(request);
69 if (retrySafe) this.ensureIdempotencyKey(request);
70 const max = this.opts.maxRetries ?? 2;
71 const now = this.opts.now ?? Date.now;
72 const start = now();
73 const signal = request.getSignal?.();
74
75 let attempt = 0;
76 for (;;) {
77 this.throwIfAborted(signal);
78
79 let resp: ResponseContext | undefined;
80 let connErr: unknown;
81 try {
82 resp = await this.inner.send(request).toPromise();
83 } catch (e) {
84 connErr = e; // connection-level failure (no HTTP response)
85 }
86
87 const isConn = resp === undefined;
88 const retryable = retrySafe && (isConn || isRetryableStatus(resp!.httpStatusCode));
89 if (!retryable || attempt >= max) {
90 if (resp !== undefined) return resp;
91 throw connErr;
92 }
93
94 const delay = this.backoffMs(attempt, resp);
95 // Total-deadline guard: don't start a wait that would blow the deadline.
96 if (this.opts.maxElapsedMs !== undefined && now() - start + delay > this.opts.maxElapsedMs) {
97 if (resp !== undefined) return resp;
98 throw connErr;
99 }
100 await this.sleep(delay, signal);
101 attempt += 1;
102 }
103 }
104
105 // Whether this request may be safely re-sent after a transient failure.
106 //
107 // Retrying a non-idempotent POST after an ambiguous failure can double-create
108 // a resource: the server commits the write, then the connection drops or a 5xx
109 // is returned, and a blind retry creates a SECOND row. So we only retry:
110 // - reads (GET/HEAD/OPTIONS) — no side effects;
111 // - HTTP-idempotent writes (PUT/PATCH/DELETE) — repeating reaches the same

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected