@salesforce/core
Version:
Core libraries to interact with SFDX projects, orgs, and APIs.
121 lines • 4.65 kB
JavaScript
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
;