@haatlabs-core/providers
v0.10.0
Published
Retry, circuit breaker, rate and concurrency limits for calling outside services.
Readme
@haatlabs-core/providers
What every caller of an outside service needs, written once: retry, a circuit breaker,
rate-limit turns, a concurrency limit and mapLimit, protect (the layers in their order),
the services-gateway contract (tiers and the headers a gateway reads), cachedCall with single-flight, and the safe fetch of
untrusted URLs (@haatlabs-core/providers/safe-fetch). Each takes any call; the error a project
throws stays the project's. It throws PROVIDER_UNAVAILABLE by default; a project spreads
PROVIDERS_ERRORS into defineErrors.
const breaker = createCircuitBreaker({ name: 'search' });
const gate = gateByRateLimit(limiter, { key: 'search', policy }, (ms) => refusal(ms));
const answer = await protect(() => call(), { gate, breaker, retry: { signal } });The root carries cachedCall, the codecs and the memory store, never the Redis one: import
createRedisCacheStore from @haatlabs-core/providers/cache, so the root's types never name
ioredis. The root loads no HTTP client either; sniffImageType is there as well as in
@haatlabs-core/providers/safe-fetch.
A fetch that failed for now (DNS, a reset, a 5xx or 429 image) is worth another attempt:
import { isTransientSafeFetchError, safeFetchImage } from '@haatlabs-core/providers/safe-fetch';
const image = await retry(() => safeFetchImage(url, { signal }), {
isRetryable: isTransientSafeFetchError,
signal,
});localTimeoutMs(timeoutMs, call) bounds an adapter's own timeout by the call's deadline, and
retryAfterMsOf(response.headers) reads a Retry-After (seconds or a date, at most 300 s).
Install
pnpm add @haatlabs-core/providersIt leaves one package to your app, so the app holds one copy: ioredis.
