chore: improve tryFetch documentation and handling

This commit is contained in:
Ben Allfree 2023-10-21 03:14:42 -07:00
parent 3bb058762a
commit a76566002d

View File

@ -1,50 +1,64 @@
import { LoggerService } from '@pockethost/common' import { LoggerService } from '@pockethost/common'
import fetch from 'node-fetch' import fetch, { Response } from 'node-fetch'
import { AsyncContext } from './AsyncContext'
export const TRYFETCH_RETRY_MS = 50 export const TRYFETCH_RETRY_MS = 50
export type Config = Required<AsyncContext> & { export type Config = {
preflight: () => Promise<boolean> preflight: () => Promise<boolean>
retryMs: number retryMs: number
} }
/**
*
* @param url The URL to fetch
* @param config { preflight: ()=>Promise<boolean>, retryMs: number}
* @returns Promise<Response>
*
* tryFetch will contiously try to fetch a URL every `retryMs`, with an optinoal `preflight`.
* If `preflight` is specificed, it must resolve to `true` before tryFetch
* will attempt to fetch the URL. If `preflight` resolves to `false`, tryFetch
* will delay by `retryMs` and then check again. If `preflight` rejects,
* then tryFetch rejects and exits.
*
* Note: tryFetch exits ONLY on success or a rejected preflight.
*/
export const tryFetch = async (url: string, config?: Partial<Config>) => { export const tryFetch = async (url: string, config?: Partial<Config>) => {
const { logger, preflight, retryMs }: Config = { const { preflight, retryMs }: Config = {
logger: LoggerService().create(`tryFetch`),
preflight: async () => true, preflight: async () => true,
retryMs: TRYFETCH_RETRY_MS, retryMs: TRYFETCH_RETRY_MS,
...config, ...config,
} }
const _logger = logger.create(`tryFetch`) const logger = LoggerService().create(`tryFetch`).breadcrumb(url)
const { dbg } = _logger const { dbg } = logger
return new Promise<void>((resolve, reject) => { return new Promise<Response>((resolve, reject) => {
const tryFetch = async () => { const again = () => setTimeout(_real_tryFetch, retryMs)
const _real_tryFetch = async () => {
if (preflight) { if (preflight) {
dbg(`Checking preflight`)
try { try {
dbg(`Preflight: CHECK`)
const shouldFetch = await preflight() const shouldFetch = await preflight()
if (!shouldFetch) { if (!shouldFetch) {
reject(new Error(`failed preflight, aborting`)) dbg(`Preflight: NOT READY`)
again()
return return
} }
dbg(`Preflight: READY`)
} catch (e) { } catch (e) {
reject(new Error(`preflight threw error, aborting`)) dbg(`Preflight: ABORT`)
reject(e)
return return
} }
} }
try { try {
dbg(`Trying to fetch ${url} `) dbg(`Fetch: START`)
const res = await fetch(url) const res = await fetch(url)
dbg(`Fetch ${url} successful`) dbg(`Fetch: SUCCESS`)
resolve() resolve(res)
} catch (e) { } catch (e) {
dbg( dbg(`Fetch: ERROR: trying again in ${retryMs}ms | ${e}`)
`Could not fetch ${url}, trying again in ${retryMs}ms. Raw error ${e}`, again()
)
setTimeout(tryFetch, retryMs)
} }
} }
tryFetch() _real_tryFetch()
}) })
} }