@temporalio/workflow
Version:
Temporal.io SDK Workflow sub-package
92 lines • 4.46 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNexusClient = createNexusClient;
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 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 createNexusClient(options) {
class NexusClientImpl {
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' ? 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);
// TODO: Do we want to make the interceptor async like we do for child workflow? That seems redundant.
// REVIEW: I ended up changing this so that the interceptor returns a Promise<StartNexusOperationOutput>,
// and the result promise is contained in that Output object. As a consequence of this,
// the result promise/completion does not exist until the StartNexusOperation event is received.
// That's totally different from what we did in ChildWorkflow, but I think that's cleaner from
// interceptors point of view, and will make it easier to extend the API in the future.
const { token, result: resultPromise } = await execute({
endpoint: options.endpoint,
service: options.service.name,
operation: opName,
options: operationOptions ?? {},
headers: {},
seq,
input,
});
return {
service: options.service.name,
operation: opName,
token,
async result() {
return resultPromise;
},
};
}
}
return new NexusClientImpl();
}
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),
// FIXME(nexus-post-initial-release): cancellationType is not supported yet
},
userMetadata: (0, user_metadata_1.userMetadataToPayload)(activator.payloadConverter, options?.summary, undefined),
});
activator.completions.nexusOperationStart.set(seq, {
resolve,
reject,
});
});
}
//# sourceMappingURL=nexus.js.map
;