UNPKG

safe-calls

Version:
74 lines (72 loc) 2.06 kB
// src/RateLimitManager.ts import pLimit from "p-limit"; import pRetry from "p-retry"; import pThrottle from "p-throttle"; var RateLimitManager = class { limiters; throttlers; configs; constructor(options = {}) { this.limiters = /* @__PURE__ */ new Map(); this.configs = /* @__PURE__ */ new Map(); this.throttlers = /* @__PURE__ */ new Map(); for (const [service, config] of Object.entries(options)) { this.#addService(service, config); } } /** * Wraps an async function with the rate limit and retry logic for the specified service. */ wrap(service, fn) { const limiter = this.limiters.get(service); const throttler = this.throttlers.get(service); const config = this.configs.get(service); if (!limiter || !throttler || !config) { throw new Error(`No rate limit configured for service: ${service}`); } return (...args) => limiter( async () => await throttler( () => pRetry(() => fn(...args), { retries: config.retries ?? 1, onFailedAttempt: (error) => { console.warn( `[${service}] Retry attempt ${error.attemptNumber} failed. ${error.message}` ); } }) )() ); } /** * Updates the configuration for an existing service. */ updateService(service, config) { if (!this.limiters.has(service)) { throw new Error(`No rate limit configured for service: ${service}`); } this.#addService(service, config); } /** * Returns the number of pending tasks for a service. */ getPendingCount(service) { return this.limiters.get(service)?.pendingCount ?? 0; } /** * Adds a new service with the given configuration. */ #addService(service, config) { this.throttlers.set( service, pThrottle({ limit: config.requestsPerInterval, interval: config.intervalMs }) ); this.limiters.set(service, pLimit(config.concurrency)); this.configs.set(service, config); } }; export { RateLimitManager };