@temporalio/workflow
Version:
Temporal.io SDK Workflow sub-package
158 lines • 8.03 kB
JavaScript
;
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