UNPKG

@zaplify/gcp-pubsub

Version:

Cloud Pub/Sub Client Library for Node.js

220 lines (219 loc) 7.12 kB
/*! * Copyright 2018 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /// <reference types="node" /> import { CallOptions, GoogleError, grpc } from 'google-gax'; import defer = require('p-defer'); import { ExponentialRetry } from './exponential-retry'; import { AckResponse, Message, Subscriber } from './subscriber'; import { DebugMessage } from './debug'; /** * @private */ export interface QueuedMessage { ackId: string; deadline?: number; responsePromise?: defer.DeferredPromise<void>; retryCount: number; } /** * @private */ export type QueuedMessages = Array<QueuedMessage>; export interface BatchOptions { callOptions?: CallOptions; maxMessages?: number; maxMilliseconds?: number; } /** * Error class used to signal a batch failure. * * Now that we have exactly-once delivery subscriptions, we'll only * throw one of these if there was an unknown error. * * @class * * @param {string} message The error message. * @param {GoogleError} err The grpc error. */ export declare class BatchError extends DebugMessage { ackIds: string[]; code: grpc.status; details: string; constructor(err: GoogleError, ackIds: string[], rpc: string); } /** * @typedef {object} BatchOptions * @property {object} [callOptions] Request configuration option, outlined * here: {@link https://googleapis.github.io/gax-nodejs/interfaces/CallOptions.html}. * @property {number} [maxMessages=3000] Maximum number of messages allowed in * each batch sent. * @property {number} [maxMilliseconds=100] Maximum duration to wait before * sending a batch. Batches can be sent earlier if the maxMessages option * is met before the configured duration has passed. */ /** * Class for buffering ack/modAck requests. * * @private * @class * * @param {Subscriber} sub The subscriber we're queueing requests for. * @param {BatchOptions} options Batching options. */ export declare abstract class MessageQueue { numPendingRequests: number; numInFlightRequests: number; numInRetryRequests: number; protected _onFlush?: defer.DeferredPromise<void>; protected _onDrain?: defer.DeferredPromise<void>; protected _options: BatchOptions; protected _requests: QueuedMessages; protected _subscriber: Subscriber; protected _timer?: NodeJS.Timer; protected _retrier: ExponentialRetry<QueuedMessage>; protected _closed: boolean; protected abstract _sendBatch(batch: QueuedMessages): Promise<QueuedMessages>; constructor(sub: Subscriber, options?: BatchOptions); /** * Shuts down this message queue gracefully. Any acks/modAcks pending in * the queue or waiting for retry will be removed. If exactly-once delivery * is enabled on the subscription, we'll send permanent failures to * anyone waiting on completions; otherwise we'll send successes. * * If a flush is desired first, do it before calling close(). * * @private */ close(): void; /** * Gets the default buffer time in ms. * * @returns {number} * @private */ get maxMilliseconds(): number; /** * Adds a message to the queue. * * @param {Message} message The message to add. * @param {number} [deadline] The deadline. * @private */ add({ ackId }: Message, deadline?: number): Promise<void>; /** * Retry handler for acks/modacks that have transient failures. Unless * it's passed the final deadline, we will just re-queue it for sending. * * @private */ private handleRetry; /** * This hook lets a subclass tell the retry handler to go ahead and fail early. * * @private */ protected shouldFailEarly(message: QueuedMessage): boolean; /** * Sends a batch of messages. * @private */ flush(): Promise<void>; /** * Returns a promise that resolves after the next flush occurs. * * @returns {Promise} * @private */ onFlush(): Promise<void>; /** * Returns a promise that resolves when all in-flight messages have settled. */ onDrain(): Promise<void>; /** * Set the batching options. * * @param {BatchOptions} options Batching options. * @private */ setOptions(options: BatchOptions): void; /** * Succeed a whole batch of Acks/Modacks for an OK RPC response. * * @private */ handleAckSuccesses(batch: QueuedMessages): void; /** * If we get an RPC failure of any kind, this will take care of deciding * what to do for each related ack/modAck. Successful ones will have their * Promises resolved, permanent errors will have their Promises rejected, * and transients will be returned for retry. * * Note that this is only used for subscriptions with exactly-once * delivery enabled, so _sendBatch() in the classes below take care of * resolving errors to success; they don't make it here. * * @private */ handleAckFailures(operation: string, batch: QueuedMessages, rpcError: GoogleError): { toError: Map<AckResponse, QueuedMessages>; toRetry: QueuedMessages; }; /** * Since we handle our own retries for ack/modAck calls when exactly-once * delivery is enabled on a subscription, we conditionally need to disable * the gax retries. This returns an appropriate CallOptions for the * subclasses to pass down. * * @private */ protected getCallOptions(): CallOptions | undefined; } /** * Queues up Acknowledge (ack) requests. * * @private * @class */ export declare class AckQueue extends MessageQueue { /** * Sends a batch of ack requests. * * @private * * @param {Array.<Array.<string|number>>} batch Array of ackIds and deadlines. * @return {Promise} */ protected _sendBatch(batch: QueuedMessages): Promise<QueuedMessages>; } /** * Queues up ModifyAckDeadline requests and sends them out in batches. * * @private * @class */ export declare class ModAckQueue extends MessageQueue { /** * Sends a batch of modAck requests. Each deadline requires its own request, * so we have to group all the ackIds by deadline and send multiple requests. * * @private * * @param {Array.<Array.<string|number>>} batch Array of ackIds and deadlines. * @return {Promise} */ protected _sendBatch(batch: QueuedMessages): Promise<QueuedMessages>; protected shouldFailEarly(message: QueuedMessage): boolean; }