diff --git a/src/constants/apis.constant.ts b/src/constants/apis.constant.ts index 1270476..2b87725 100644 --- a/src/constants/apis.constant.ts +++ b/src/constants/apis.constant.ts @@ -4,3 +4,5 @@ export const apis = { auctions: "v2/auctions", events: "v2/events", }; + +export const retryableStatusCodes = [429, 500, 502, 503, 504]; diff --git a/src/functions/events.ts b/src/functions/events.ts index 83414e3..28ff37a 100644 --- a/src/functions/events.ts +++ b/src/functions/events.ts @@ -2,7 +2,7 @@ import { apis, baseURL } from "../constants/apis.constant"; import APIClient from "../lib/api-client"; import AppError from "../lib/app-error"; import { withValidation } from "../lib/with-validation"; -import type { TopsortEvent } from "../types/events"; +import type { EventResult, TopsortEvent } from "../types/events"; import type { Config } from "../types/shared"; /** @@ -18,9 +18,9 @@ import type { Config } from "../types/shared"; * * @param config - The configuration object containing the API Key and optionally, the Host. * @param event - The event to report. - * @returns {Promise<{ok: boolean}>} The result of the report, indicating success. + * @returns {Promise} The result of the report, indicating success. */ -async function handler(config: Config, event: TopsortEvent): Promise<{ ok: boolean }> { +async function handler(config: Config, event: TopsortEvent): Promise { let url: URL; try { url = new URL(`${config.host || baseURL}/${apis.events}`); @@ -30,11 +30,15 @@ async function handler(config: Config, event: TopsortEvent): Promise<{ ok: boole }); } - await APIClient.post(url.toString(), event, config); - - return { - ok: true, - }; + try { + await APIClient.post(url.toString(), event, config); + return { ok: true, retry: false }; + } catch (error) { + if (error instanceof AppError && error.retry) { + return { ok: false, retry: true }; + } + throw error; + } } export const reportEvent = withValidation(handler); diff --git a/src/lib/api-client.ts b/src/lib/api-client.ts index e7a0d32..af7bb75 100644 --- a/src/lib/api-client.ts +++ b/src/lib/api-client.ts @@ -1,5 +1,5 @@ import { version } from "../../package.json"; -import { baseURL } from "../constants/apis.constant"; +import { baseURL, retryableStatusCodes } from "../constants/apis.constant"; import type { Config } from "../types/shared"; import AppError from "./app-error"; @@ -20,7 +20,8 @@ class APIClient { } if (!response.ok) { - throw new AppError(response.status, response.statusText, data); + const retry = retryableStatusCodes.includes(response.status); + throw new AppError(response.status, response.statusText, data, retry); } return data; diff --git a/src/lib/app-error.ts b/src/lib/app-error.ts index 35e6201..3675c11 100644 --- a/src/lib/app-error.ts +++ b/src/lib/app-error.ts @@ -2,11 +2,13 @@ class AppError { public readonly status: number; //change later to http status code public readonly statusText: string; public readonly body: unknown; + public readonly retry: boolean; - constructor(status: number, statusText: string, body: unknown) { + constructor(status: number, statusText: string, body: unknown, retry = false) { this.status = status; this.statusText = statusText; this.body = body; + this.retry = retry; } } diff --git a/src/types/events.d.ts b/src/types/events.d.ts index 73952b2..8a311b1 100644 --- a/src/types/events.d.ts +++ b/src/types/events.d.ts @@ -45,3 +45,8 @@ export interface TopsortEvent { clicks?: Click[]; purchases?: Purchase[]; } + +export interface EventResult { + ok: boolean; + retry: boolean; +}