fix: Anify timeout logic running even when fetch resolved

Summary:

Test Plan:
This commit is contained in:
2024-05-26 13:22:03 -04:00
parent 00ff0e0295
commit 6e8fe4f7b0
3 changed files with 64 additions and 11 deletions

View File

@@ -1,3 +1,4 @@
import { PromiseTimedOutError, promiseTimeout } from "~/libs/promiseTimeout";
import { sortByProperty } from "~/libs/sortByProperty";
import type { EpisodesResponse } from "./episode";
@@ -11,22 +12,18 @@ export async function getEpisodesFromAnify(
}
let response: AnifyEpisodesResponse[] | null = null;
try {
const abortController = new AbortController();
response = await Promise.race([
try {
response = await promiseTimeout(
fetch(`https://api.anify.tv/episodes/${aniListId}`, {
signal: abortController.signal,
}).then((res) => res.json<AnifyEpisodesResponse[]>()),
// set a limit of 30 seconds
new Promise((resolve) => setTimeout(resolve, 30 * 1000)).then(() => {
abortController.abort("Loading episodes from Anify timed out");
console.error(
`Loading episodes from Anify timed out; aniListId: ${aniListId}`,
30 * 1000,
);
return null;
}),
]);
} catch (e) {
if (e instanceof PromiseTimedOutError) {
abortController.abort("Loading episodes from Anify timed out");
}
console.error(
new Error(
`Error trying to load episodes from anify; aniListId: ${aniListId}`,

View File

@@ -0,0 +1,29 @@
import { describe, expect, it } from "bun:test";
import { PromiseTimedOutError, promiseTimeout } from "./promiseTimeout";
describe("promiseTimeout", () => {
it("promise resolves within timeout, returns value", () => {
expect(
promiseTimeout(
wait(1).then(() => 2),
2,
),
).resolves.toBe(2);
});
it("promise does not resolve within timeout, throws PromiseTimedOutError", () => {
expect(
promiseTimeout(
wait(2).then(() => 2),
1,
),
).rejects.toThrow(PromiseTimedOutError);
});
});
function wait(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

View File

@@ -0,0 +1,27 @@
export function promiseTimeout<T>(
promise: Promise<T>,
timeoutMs: number,
): Promise<T | null> {
let hasPromiseResolved = false;
return Promise.race([
promise.then((value) => {
hasPromiseResolved = true;
return value;
}),
new Promise((resolve) => setTimeout(resolve, timeoutMs)).then(() => {
if (hasPromiseResolved) {
return null;
}
throw new PromiseTimedOutError();
}),
]);
}
export class PromiseTimedOutError extends Error {
constructor(message?: string) {
super(message ?? "Promise timed out");
this.name = "PromiseTimedOutError";
}
}