Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
1.8 kB ยท 67 lines
TypeScript
at apifix
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768import { Effect, Schedule } from "effect";
export class WebhookSendError extends Error { readonly httpStatus?: number;
constructor( message: string, opts?: { httpStatus?: number; cause?: unknown }, ) { super(message, { cause: opts?.cause }); this.name = "WebhookSendError"; this.httpStatus = opts?.httpStatus; }}
// Network errors and timeouts (no status) are transient; 5xx and 429 may clear.// Other 4xx are client errors that won't succeed on retry.const isRetryable = (err: WebhookSendError): boolean => err.httpStatus === undefined || err.httpStatus >= 500 || err.httpStatus === 429;
const retryPolicy = { schedule: Schedule.exponential("200 millis").pipe(Schedule.jittered), times: 3, while: isRetryable,};
/** * POST to a webhook with exponential-backoff retries on transient failures. * Rejects with `WebhookSendError` once retries are exhausted. */export function postWebhookWithRetry(opts: { url: string; headers: Record<string, string>; body: string; timeoutMs: number;}): Promise<void> { const send = Effect.tryPromise({ try: (signal) => fetch(opts.url, { method: "POST", headers: opts.headers, body: opts.body, signal, }), catch: (cause) => new WebhookSendError("Webhook request failed", { cause }), }).pipe( Effect.timeoutFail({ duration: `${opts.timeoutMs} millis`, onTimeout: () => new WebhookSendError(`Webhook timed out after ${opts.timeoutMs}ms`), }), Effect.flatMap((response) => response.ok ? Effect.void : Effect.fail( new WebhookSendError(`Webhook returned ${response.status}`, { httpStatus: response.status, }), ), ), Effect.retry(retryPolicy), );
return Effect.runPromise(send);}