feat: timeout and retry fetches in proxy (#45)
* feat: timeout and retry fetches in proxy * chore: fmt * feat: move fetch changes to a shim in getFetchClient * chore: fmt * chore: remove unused import * chore: fetch => globalThis.fetch * chore: remove redundant use of async/await in promise-returning function * feat: add initial configuration checks * fix: use RequestInit directly * fix: use networking subsection with kongfigStore * chore: update fetch_timeout configuration value to fetch_timeout_ms
This commit is contained in:
parent
c0dafb1f7d
commit
3574d91d9f
2 changed files with 52 additions and 10 deletions
|
@ -16,6 +16,11 @@ directory = "/var/tmp"
|
|||
#proxy = ""
|
||||
# Enable YouTube new video format UMP
|
||||
ump = false
|
||||
# fetch_timeout_ms = 10000
|
||||
# fetch_retry_enable = true
|
||||
# fetch_retry_times = 3
|
||||
# fetch_retry_initial_debounce = 500
|
||||
# fetch_retry_debounce_multiplier = 2
|
||||
|
||||
[jobs]
|
||||
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
import { Store } from "@willsoto/node-konfig-core";
|
||||
import { retry, type RetryOptions } from "jsr:@std/async";
|
||||
|
||||
type FetchInputParameter = Parameters<typeof fetch>[0];
|
||||
type FetchInitParameterWithClient =
|
||||
| RequestInit
|
||||
| RequestInit & { client: Deno.HttpClient };
|
||||
type FetchReturn = ReturnType<typeof fetch>;
|
||||
|
||||
export const getFetchClient = (konfigStore: Store): {
|
||||
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
||||
(
|
||||
input: Request | URL | string,
|
||||
init?: RequestInit & {
|
||||
client: Deno.HttpClient;
|
||||
},
|
||||
): Promise<Response>;
|
||||
(input: URL | Request | string, init?: RequestInit): Promise<Response>;
|
||||
input: FetchInputParameter,
|
||||
init?: FetchInitParameterWithClient,
|
||||
): FetchReturn;
|
||||
} => {
|
||||
if (Deno.env.get("PROXY") || konfigStore.get("networking.proxy")) {
|
||||
return async (
|
||||
input: RequestInfo | URL,
|
||||
input: FetchInputParameter,
|
||||
init?: RequestInit,
|
||||
) => {
|
||||
const client = Deno.createHttpClient({
|
||||
|
@ -21,7 +24,7 @@ export const getFetchClient = (konfigStore: Store): {
|
|||
konfigStore.get("networking.proxy") as string,
|
||||
},
|
||||
});
|
||||
const fetchRes = await fetch(input, {
|
||||
const fetchRes = await fetchShim(konfigStore, input, {
|
||||
client,
|
||||
headers: init?.headers,
|
||||
method: init?.method,
|
||||
|
@ -34,5 +37,39 @@ export const getFetchClient = (konfigStore: Store): {
|
|||
};
|
||||
}
|
||||
|
||||
return globalThis.fetch;
|
||||
return (input: FetchInputParameter, init?: FetchInitParameterWithClient) =>
|
||||
fetchShim(konfigStore, input, init);
|
||||
};
|
||||
|
||||
function fetchShim(
|
||||
konfigStore: Store,
|
||||
input: FetchInputParameter,
|
||||
init?: FetchInitParameterWithClient,
|
||||
): FetchReturn {
|
||||
const fetchTimeout = konfigStore.get("networking.fetch_timeout_ms");
|
||||
const fetchRetry = konfigStore.get("networking.fetch_retry_enable");
|
||||
const fetchMaxAttempts = konfigStore.get("networking.fetch_retry_times");
|
||||
const fetchInitialDebounce = konfigStore.get(
|
||||
"networking.fetch_retry_initial_debounce",
|
||||
);
|
||||
const fetchDebounceMultiplier = konfigStore.get(
|
||||
"networking.fetch_retry_debounce_multiplier",
|
||||
);
|
||||
const retryOptions: RetryOptions = {
|
||||
maxAttempts: Number(fetchMaxAttempts) || 1,
|
||||
minTimeout: Number(fetchInitialDebounce) || 0,
|
||||
multiplier: Number(fetchDebounceMultiplier) || 0,
|
||||
jitter: 0,
|
||||
};
|
||||
|
||||
const callFetch = () =>
|
||||
fetch(input, {
|
||||
// only set the AbortSignal if the timeout is supplied in the config
|
||||
signal: fetchTimeout
|
||||
? AbortSignal.timeout(Number(fetchTimeout))
|
||||
: null,
|
||||
...(init || {}),
|
||||
});
|
||||
// if retry enabled, call retry with the fetch shim, otherwise pass the fetch shim back directly
|
||||
return fetchRetry ? retry(callFetch, retryOptions) : callFetch();
|
||||
}
|
||||
|
|
Reference in a new issue