UNPKG

@salesforce/core

Version:

Core libraries to interact with SFDX projects, orgs, and APIs.

121 lines 4.65 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PollingClient = void 0; /* * Copyright (c) 2020, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ const kit_1 = require("@salesforce/kit"); const ts_types_1 = require("@salesforce/ts-types"); const ts_retry_promise_1 = require("ts-retry-promise"); const logger_1 = require("../logger/logger"); const sfError_1 = require("../sfError"); const lifecycleEvents_1 = require("../lifecycleEvents"); /** * This is a polling client that can be used to poll the status of long running tasks. It can be used as a replacement * for Streaming when streaming topics are not available or when streaming handshakes are failing. Why wouldn't you * want to use this? It can impact Salesforce API usage. * * ``` * const options: PollingClient.Options = { * async poll(): Promise<StatusResult> { * return Promise.resolve({ completed: true, payload: 'Hello World' }); * }, * frequency: Duration.milliseconds(10), * timeout: Duration.minutes(1) * }; * const client = await PollingClient.create(options); * const pollResult = await client.subscribe(); * console.log(`pollResult: ${pollResult}`); * ``` */ class PollingClient extends kit_1.AsyncOptionalCreatable { logger; options; /** * Constructor * * @param options Polling client options * @ignore */ constructor(options) { super(options); this.options = (0, ts_types_1.ensure)(options); } /** * Asynchronous initializer. */ async init() { this.logger = await logger_1.Logger.child(this.constructor.name); } /** * Returns a promise to call the specified polling function using the interval and timeout specified * in the polling options. */ async subscribe() { let errorInPollingFunction; // keep this around for returning in the catch block const doPoll = async () => { let result; try { result = await this.options.poll(); } catch (error) { const err = (errorInPollingFunction = error); if (['ETIMEDOUT', 'ENOTFOUND', 'ECONNRESET', 'socket hang up'].some((retryableNetworkError) => err.message.includes(retryableNetworkError))) { this.logger.debug('Network error on the request', err); await lifecycleEvents_1.Lifecycle.getInstance().emitWarning('Network error occurred. Continuing to poll.'); throw sfError_1.SfError.wrap(err); } // there was an actual error thrown, so we don't want to keep retrying throw new ts_retry_promise_1.NotRetryableError(err.name); } if (result.completed) { return result.payload; } throw new Error('Operation did not complete. Retrying...'); // triggers a retry }; const finalResult = (0, ts_retry_promise_1.retryDecorator)(doPoll, { timeout: this.options.timeout.milliseconds, delay: this.options.frequency.milliseconds, retries: 'INFINITELY', }); try { return await finalResult(); } catch (error) { if (errorInPollingFunction) { throw errorInPollingFunction; } await lifecycleEvents_1.Lifecycle.getInstance().emit('POLLING_TIME_OUT', error); this.logger.debug('Polling timed out'); throw new sfError_1.SfError('The client has timed out.', this.options.timeoutErrorName ?? 'PollingClientTimeout'); } } } exports.PollingClient = PollingClient; (function (PollingClient) { /** * Default options set for polling. The default options specify a timeout of 3 minutes and polling frequency of 15 * seconds; */ class DefaultPollingOptions { frequency; poll; timeout; /** * constructor * * @param poll The function used for polling status. * {@link StatusResult} */ constructor(poll) { this.poll = poll; this.timeout = kit_1.Duration.minutes(3); this.frequency = kit_1.Duration.seconds(15); } } PollingClient.DefaultPollingOptions = DefaultPollingOptions; })(PollingClient || (exports.PollingClient = PollingClient = {})); //# sourceMappingURL=pollingClient.js.map