import { PersistentCache } from "./cache";
export declare class Deferred<T = void> {
    promise: Promise<T>;
    resolve: (arg: T | PromiseLike<T>) => void;
    reject: (err?: any) => void;
    constructor();
}
export declare class DeferredWorker<T = void> extends Deferred<T> {
    private worker;
    private cancel?;
    constructor(worker: () => Promise<T>, cancel?: (() => string | undefined) | undefined);
    execute(): Promise<void>;
}
export type RetryType = number | ((err: any, retries: number) => boolean);
export declare function retryOp<T>(retryN: RetryType, fn: (retries: number) => Promise<T>): Promise<T>;
export declare class Funnel<T = void> {
    concurrency: number;
    protected shouldRetry?: RetryType | undefined;
    protected pendingQueue: Set<DeferredWorker<T>>;
    protected executingQueue: Set<DeferredWorker<T>>;
    processed: number;
    errors: number;
    constructor(concurrency?: number, shouldRetry?: RetryType | undefined);
    push(worker: () => Promise<T>, shouldRetry?: RetryType, cancel?: () => string | undefined): Promise<T>;
    clear(): void;
    promises(): Promise<T>[];
    all(): Promise<(void | Awaited<T>)[]>;
    size(): number;
    setMaxConcurrency(maxConcurrency: number): void;
    getConcurrency(): number;
    protected doWork(): void;
}
/**
 * @internal
 */
export interface PumpOptions {
    concurrency: number;
    verbose?: boolean;
}
/**
 * @internal
 */
export declare class Pump<T = void> extends Funnel<T | void> {
    protected options: PumpOptions;
    protected worker: () => Promise<T>;
    stopped: boolean;
    constructor(options: PumpOptions, worker: () => Promise<T>);
    start(): void;
    stop(): void;
    drain(): Promise<(void | Awaited<T>)[]>;
    setMaxConcurrency(concurrency: number): void;
}
export declare class RateLimiter<T = void> {
    protected targetRequestsPerSecond: number;
    protected burst: number;
    protected lastTick: number;
    protected bucket: number;
    protected queue: Set<DeferredWorker<T>>;
    constructor(targetRequestsPerSecond: number, burst?: number);
    push(worker: () => Promise<T>, cancel?: () => string | undefined): Promise<T>;
    protected updateBucket(): void;
    protected drainQueue(): Promise<void>;
    clear(): void;
}
/**
 * Specify {@link throttle} limits. These limits shape the way throttle invokes
 * the underlying function.
 * @public
 */
export interface Limits {
    /**
     * The maximum number of concurrent executions of the underlying function to
     * allow. Must be supplied, there is no default. Specifying `0` or
     * `Infinity` is allowed and means there is no concurrency limit.
     */
    concurrency: number;
    /**
     * The maximum number of calls per second to allow to the underlying
     * function. Default: no rate limit.
     */
    rate?: number;
    /**
     * The maximum number of calls to the underlying function to "burst" -- e.g.
     * the number that can be issued immediately as long as the rate limit is
     * not exceeded. For example, if rate is 5 and burst is 5, and 10 calls are
     * made to the throttled function, 5 calls are made immediately and then
     * after 1 second, another 5 calls are made immediately. Setting burst to 1
     * means calls are issued uniformly every `1/rate` seconds. If `rate` is not
     * specified, then `burst` does not apply. Default: 1.
     */
    burst?: number;
    /**
     * Retry if the throttled function returns a rejected promise. `retry` can
     * be a number or a function. If it is a number `N`, then up to `N`
     * additional attempts are made in addition to the initial call. If retry is
     * a function, it should return `true` if another retry attempt should be
     * made, otherwise `false`. The first argument will be the value of the
     * rejected promise from the previous call attempt, and the second argument
     * will be the number of previous retry attempts (e.g. the first call will
     * have value 0). Default: 0 (no retry attempts).
     */
    retry?: number | ((err: any, retries: number) => boolean);
    /**
     * If `memoize` is `true`, then every call to the throttled function will be
     * saved as an entry in a map from arguments to return value. If same
     * arguments are seen again in a future call, the return value is retrieved
     * from the Map rather than calling the function again. This can be useful
     * for avoiding redundant calls that are expected to return the same results
     * given the same arguments.
     *
     * The arguments will be captured with `JSON.stringify`, therefore types
     * that do not stringify uniquely won't be distinguished from each other.
     * Care must be taken when specifying `memoize` to ensure avoid incorrect
     * results.
     */
    memoize?: boolean;
    /**
     * Similar to `memoize` except the map from function arguments to results is
     * stored in a persistent cache on disk. This is useful to prevent redundant
     * calls to APIs which are expected to return the same results for the same
     * arguments, and which are likely to be called across many faast.js module
     * instantiations. This is used internally by faast.js for caching cloud
     * prices for AWS, and for saving the last garbage collection
     * date for AWS. Persistent cache entries expire after a period of time. See
     * {@link PersistentCache}.
     */
    cache?: PersistentCache;
    /**
     * A promise that, if resolved, causes cancellation of pending throttled
     * invocations. This is typically created using `Deferred`. The idea is to
     * use the resolving of the promise as an asynchronous signal that any
     * pending invocations in this throttled function should be cleared.
     * @internal
     */
    cancel?: Promise<void>;
}
export declare function memoizeFn<A extends any[], R>(fn: (...args: A) => R, cache?: Map<string, R>): (...args: A) => R;
export declare function cacheFn<A extends any[], R>(cache: PersistentCache, fn: (...args: A) => Promise<R>): (...args: A) => Promise<any>;
/**
 * A decorator for rate limiting, concurrency limiting, retry, memoization, and
 * on-disk caching. See {@link Limits}.
 * @remarks
 * When programming against cloud services, databases, and other resources, it
 * is often necessary to control the rate of request issuance to avoid
 * overwhelming the service provider. In many cases the provider has built-in
 * safeguards against abuse, which automatically fail requests if they are
 * coming in too fast. Some systems don't have safeguards and precipitously
 * degrade their service level or fail outright when faced with excessive load.
 *
 * With faast.js it becomes very easy to (accidentally) generate requests from
 * thousands of cloud functions. The `throttle` function can help manage request
 * flow without resorting to setting up a separate service. This is in keeping
 * with faast.js' zero-ops philosophy.
 *
 * Usage is simple:
 *
 * ```typescript
 * async function operation() { ... }
 * const throttledOperation = throttle({ concurrency: 10, rate: 5 }, operation);
 * for(let i = 0; i < 100; i++) {
 *     // at most 10 concurrent executions at a rate of 5 invocations per second.
 *     throttledOperation();
 * }
 * ```
 *
 * Note that each invocation to `throttle` creates a separate function with a
 * separate limits. Therefore it is likely that you want to use `throttle` in a
 * global context, not within a dynamic context:
 *
 * ```typescript
 * async function operation() { ... }
 * for(let i = 0; i < 100; i++) {
 *     // WRONG - each iteration creates a separate throttled function that's only called once.
 *     const throttledOperation = throttle({ concurrency: 10, rate: 5 }, operation);
 *     throttledOperation();
 * }
 * ```
 *
 * A better way to use throttle avoids creating a named `operation` function
 * altogether, ensuring it cannot be accidentally called without throttling:
 *
 * ```typescript
 * const operation = throttle({ concurrency: 10, rate: 5 }, async () => {
 *     ...
 * });
 * ```
 *
 * Throttle supports functions with arguments automatically infers the correct
 * type for the returned function:
 *
 * ```typescript
 * // `operation` inferred to have type (str: string) => Promise<string>
 * const operation = throttle({ concurrency: 10, rate: 5 }, async (str: string) => {
 *     return string;
 * });
 * ```
 *
 * In addition to limiting concurrency and invocation rate, `throttle` also
 * supports retrying failed invocations, memoizing calls, and on-disk caching.
 * See {@link Limits} for details.
 *
 * @param limits - see {@link Limits}.
 * @param fn - The function to throttle. It can take any arguments, but must
 * return a Promise (which includes `async` functions).
 * @returns Returns a throttled function with the same signature as the argument
 * `fn`.
 * @public
 */
export declare function throttle<A extends any[], R>(limits: Limits, fn: (...args: A) => Promise<R>): (...args: A) => Promise<R>;
export declare class AsyncQueue<T> {
    protected deferred: Array<Deferred<T>>;
    protected enqueued: Promise<T>[];
    enqueue(value: T | Promise<T>): void;
    next(): Promise<T>;
    clear(): void;
}
export declare class AsyncIterableQueue<T> extends AsyncQueue<IteratorResult<T>> {
    push(value: T | Promise<T>): void;
    done(): void;
    [Symbol.asyncIterator](): this;
}
export declare class AsyncOrderedQueue<T> {
    protected queue: AsyncQueue<T>;
    protected arrived: Map<number, Promise<T>>;
    protected current: number;
    push(value: T | Promise<T>, sequence: number): void;
    pushImmediate(value: T | Promise<T>): void;
    enqueue(value: Promise<T>, sequence: number): void;
    next(): Promise<T>;
    clear(): void;
}
