UNPKG

@temporalio/workflow

Version:
158 lines 8.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NexusOperationCancellationType = void 0; exports.createNexusServiceClient = createNexusServiceClient; const time_1 = require("@temporalio/common/lib/time"); const user_metadata_1 = require("@temporalio/common/lib/user-metadata"); const interceptors_1 = require("@temporalio/common/lib/interceptors"); const enums_helpers_1 = require("@temporalio/common/lib/internal-workflow/enums-helpers"); const cancellation_scope_1 = require("./cancellation-scope"); const global_attributes_1 = require("./global-attributes"); const stack_helpers_1 = require("./stack-helpers"); /** * Create a Nexus client for invoking Nexus Operations from a Workflow. * * @experimental Nexus support in Temporal SDK is experimental. */ function createNexusServiceClient(options) { class NexusServiceClientImpl { async executeOperation(operation, input, operationOptions) { const handle = await this.startOperation(operation, input, operationOptions); return await handle.result(); } async startOperation(operation, input, operationOptions) { const opName = typeof operation === 'string' ? // Casting as string to cover up the fact that `opName` might be undefined. // If this happens, then `execute` will produce a `NexusOperationFailure.NOT_FOUND`. options.service.operations[operation]?.name : operation.name; const activator = (0, global_attributes_1.getActivator)(); const seq = activator.nextSeqs.nexusOperation++; const execute = (0, interceptors_1.composeInterceptors)(activator.interceptors.outbound, 'startNexusOperation', startNexusOperationNextHandler); // The interceptor returns a Promise<StartNexusOperationOutput>, with the result promise contained // in that Output object. As a consequence of this, the result promise/completion does not exist // until the StartNexusOperation event is received. This is totally different from what we did in // ChildWorkflow, but is much cleaner from the interceptors point of view. const { token, result: resultPromise } = await execute({ endpoint: options.endpoint, service: options.service.name, operation: opName, options: { ...operationOptions, cancellationType: operationOptions?.cancellationType ?? 'WAIT_CANCELLATION_COMPLETED', }, headers: {}, seq, input, }); return { service: options.service.name, operation: opName, token, async result() { return resultPromise; }, }; } } return new NexusServiceClientImpl(); } function startNexusOperationNextHandler({ input, endpoint, service, options, operation, seq, headers, }) { const activator = (0, global_attributes_1.getActivator)(); return new Promise((resolve, reject) => { const scope = cancellation_scope_1.CancellationScope.current(); if (scope.consideredCancelled) { (0, stack_helpers_1.untrackPromise)(scope.cancelRequested.catch(reject)); return; } if (scope.cancellable) { (0, stack_helpers_1.untrackPromise)(scope.cancelRequested.catch(() => { const completed = !activator.completions.nexusOperationStart.has(seq) && !activator.completions.nexusOperationComplete.has(seq); if (!completed) { activator.pushCommand({ requestCancelNexusOperation: { seq }, }); } // Nothing to cancel otherwise })); } activator.pushCommand({ scheduleNexusOperation: { seq, endpoint, service, operation, nexusHeader: headers, input: activator.payloadConverter.toPayload(input), scheduleToCloseTimeout: (0, time_1.msOptionalToTs)(options?.scheduleToCloseTimeout), scheduleToStartTimeout: (0, time_1.msOptionalToTs)(options?.scheduleToStartTimeout), startToCloseTimeout: (0, time_1.msOptionalToTs)(options?.startToCloseTimeout), cancellationType: encodeNexusOperationCancellationType(options?.cancellationType), }, userMetadata: (0, user_metadata_1.userMetadataToPayload)(activator.payloadConverter, options?.summary, undefined), }); activator.completions.nexusOperationStart.set(seq, { resolve, reject, }); }); } /** * Determines: * - whether cancellation requests should be propagated from the Workflow to the Nexus Operation * - whether and when should the Operation's cancellation be reported back to the Workflow * (i.e. at which moment should the operation's result promise fail with a `NexusOperationFailure`, * with `cause` set to a `CancelledFailure`). * * Note that this setting only applies to cancellation originating from an external request for the * Workflow itself, or from internal cancellation of the `CancellationScope` in which the * Operation call was made. * * @experimental Nexus support in Temporal SDK is experimental. */ // MAINTENANCE: Keep this typedoc in sync with the `StartNexusOperationOptions.cancellationType` field exports.NexusOperationCancellationType = { /** * Do not propagate cancellation requests to the Nexus Operation, and immediately report * cancellation to the caller. */ ABANDON: 'ABANDON', /** * Initiate a cancellation request for the Nexus operation and immediately report cancellation to * the caller. Note that it doesn't guarantee that cancellation is delivered to the operation if * calling workflow exits before the delivery is done. If you want to ensure that cancellation is * delivered to the operation, use {@link WAIT_CANCELLATION_REQUESTED}. * * Propagate cancellation request from the Workflow to the Operation, yet _immediately_ report * cancellation to the caller, i.e. without waiting for the server to confirm the cancellation * request. * * Note that this cancellation type provides no guarantee, from the Workflow-side, that the * cancellation request will be delivered to the Operation Handler. In particular, either the * Operation or the Workflow may complete (either successfully or uncessfully) before the * cancellation request is delivered, resulting in a situation where the Operation completed * successfully, but the Workflow thinks it was cancelled. * * To guarantee that the Operation will eventually be notified of the cancellation request, * use {@link WAIT_CANCELLATION_REQUESTED}. */ TRY_CANCEL: 'TRY_CANCEL', /** * Propagate cancellation request from the Workflow to the Operation, then wait for the server * to confirm that the Operation cancellation request was delivered to the Operation Handler. */ WAIT_CANCELLATION_REQUESTED: 'WAIT_CANCELLATION_REQUESTED', /** * Propagate cancellation request from the Workflow to the Operation, then wait for completion * of the Operation. */ WAIT_CANCELLATION_COMPLETED: 'WAIT_CANCELLATION_COMPLETED', }; const [encodeNexusOperationCancellationType, _] = (0, enums_helpers_1.makeProtoEnumConverters)({ [exports.NexusOperationCancellationType.WAIT_CANCELLATION_COMPLETED]: 0, [exports.NexusOperationCancellationType.ABANDON]: 1, [exports.NexusOperationCancellationType.TRY_CANCEL]: 2, [exports.NexusOperationCancellationType.WAIT_CANCELLATION_REQUESTED]: 3, }, ''); //# sourceMappingURL=nexus.js.map