@temporalio/worker
Version:
Temporal.io SDK Worker sub-package
304 lines • 14.9 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isCodeBundleOption = isCodeBundleOption;
exports.isPathBundleOption = isPathBundleOption;
exports.defaultSinks = defaultSinks;
exports.appendDefaultInterceptors = appendDefaultInterceptors;
exports.compileWorkerOptions = compileWorkerOptions;
exports.toNativeWorkerOptions = toNativeWorkerOptions;
exports.toNativeTaskPollerBehavior = toNativeTaskPollerBehavior;
const os = __importStar(require("node:os"));
const v8 = __importStar(require("node:v8"));
const time_1 = require("@temporalio/common/lib/time");
const internal_non_workflow_1 = require("@temporalio/common/lib/internal-non-workflow");
const activity_log_interceptor_1 = require("./activity-log-interceptor");
const logger_1 = require("./workflow/logger");
const metrics_1 = require("./workflow/metrics");
const runtime_1 = require("./runtime");
const utils_1 = require("./utils");
const worker_tuner_1 = require("./worker-tuner");
function isCodeBundleOption(bundleOpt) {
const opt = bundleOpt; // Cast to access properties without TS complaining
return typeof opt.code === 'string';
}
function isPathBundleOption(bundleOpt) {
const opt = bundleOpt; // Cast to access properties without TS complaining
return typeof opt.codePath === 'string';
}
// Sinks and Interceptors //////////////////////////////////////////////////////////////////////////
/**
* Build the sink used internally by the SDK to forwards log messages from the Workflow sandbox to an actual logger.
*
* @param logger a {@link Logger} - defaults to the {@link Runtime} singleton logger.
* @deprecated Calling `defaultSink()` is no longer required. To configure a custom logger, set the
* {@link Runtime.logger} property instead.
*/
// eslint-disable-next-line deprecation/deprecation
function defaultSinks(logger) {
// initLoggerSink() returns a sink that complies to the new LoggerSinksInternal API (ie. named __temporal_logger), but
// code that is still calling defaultSinks() expects return type to match the deprecated LoggerSinks API. Silently
// cast just to mask type checking issues, even though we know this is wrong. Users shouldn't call functions directly
// on the returned object anyway.
// If no logger was provided, the legacy behavior was to _lazily_ set the sink's logger to the Runtime's logger.
// This was required because we may call defaultSinks() before the Runtime is initialized. We preserve that behavior
// here by silently not initializing the sink if no logger is provided.
// eslint-disable-next-line deprecation/deprecation
if (!logger)
return {};
// eslint-disable-next-line deprecation/deprecation
return (0, logger_1.initLoggerSink)(logger);
}
/**
* Appends the default Worker logging interceptors to given interceptor arrays.
*
* @param logger a {@link Logger} - defaults to the {@link Runtime} singleton logger.
*
* @deprecated Calling `appendDefaultInterceptors()` is no longer required. To configure a custom logger, set the
* {@link Runtime.logger} property instead.
*/
function appendDefaultInterceptors(interceptors, logger) {
if (!logger || logger === runtime_1.Runtime.instance().logger)
return interceptors;
return {
activityInbound: [
// eslint-disable-next-line deprecation/deprecation
(ctx) => new activity_log_interceptor_1.ActivityInboundLogInterceptor(ctx, logger),
// eslint-disable-next-line deprecation/deprecation
...(interceptors.activityInbound ?? []),
],
activity: interceptors.activity,
workflowModules: interceptors.workflowModules,
};
}
function compileWorkerInterceptors({ activity, activityInbound, // eslint-disable-line deprecation/deprecation
workflowModules, }) {
return {
activity: [...activityInbound.map((factory) => (ctx) => ({ inbound: factory(ctx) })), ...activity],
workflowModules,
};
}
function addDefaultWorkerOptions(options, logger, metricMeter) {
const { buildId, // eslint-disable-line deprecation/deprecation
useVersioning, // eslint-disable-line deprecation/deprecation
maxCachedWorkflows, showStackTraceSources, namespace, sinks, nonStickyToStickyPollRatio, interceptors, maxConcurrentActivityTaskExecutions, maxConcurrentLocalActivityExecutions, maxConcurrentWorkflowTaskExecutions, workflowTaskPollerBehavior, activityTaskPollerBehavior, ...rest } = options;
const debugMode = options.debugMode || isSet(process.env.TEMPORAL_DEBUG);
const reuseV8Context = options.reuseV8Context ?? true;
const heapSizeMiB = v8.getHeapStatistics().heap_size_limit / utils_1.MiB;
const defaultMaxCachedWorkflows = reuseV8Context
? Math.max(Math.floor((Math.max(heapSizeMiB - 200, 0) * 600) / 1024), 10)
: Math.max(Math.floor((Math.max(heapSizeMiB - 400, 0) * 250) / 1024), 10);
if (useVersioning && !buildId) {
throw new TypeError('Must provide a buildId if useVersioning is true');
}
// Difficult to predict appropriate poll numbers for resource based slots
let maxWFTPolls = 10;
let maxATPolls = 10;
let setTuner;
if (rest.tuner !== undefined) {
if (maxConcurrentActivityTaskExecutions !== undefined) {
throw new TypeError('Cannot set both tuner and maxConcurrentActivityTaskExecutions');
}
if (maxConcurrentLocalActivityExecutions !== undefined) {
throw new TypeError('Cannot set both tuner and maxConcurrentLocalActivityExecutions');
}
if (maxConcurrentWorkflowTaskExecutions !== undefined) {
throw new TypeError('Cannot set both tuner and maxConcurrentWorkflowTaskExecutions');
}
setTuner = rest.tuner;
}
else {
const maxWft = maxConcurrentWorkflowTaskExecutions ?? 40;
maxWFTPolls = Math.min(10, maxWft);
const maxAT = maxConcurrentActivityTaskExecutions ?? 100;
maxATPolls = Math.min(10, maxAT);
const maxLAT = maxConcurrentLocalActivityExecutions ?? 100;
setTuner = {
workflowTaskSlotSupplier: {
type: 'fixed-size',
numSlots: maxWft,
},
activityTaskSlotSupplier: {
type: 'fixed-size',
numSlots: maxAT,
},
localActivityTaskSlotSupplier: {
type: 'fixed-size',
numSlots: maxLAT,
},
};
}
const createPollerBehavior = (defaultMax, behavior) => !behavior
? { type: 'simple-maximum', maximum: defaultMax }
: behavior.type === 'simple-maximum'
? { type: 'simple-maximum', maximum: behavior.maximum ?? defaultMax }
: {
type: 'autoscaling',
minimum: behavior.minimum ?? 1,
initial: behavior.initial ?? 5,
maximum: behavior.maximum ?? 100,
};
const wftPollerBehavior = createPollerBehavior(maxWFTPolls, workflowTaskPollerBehavior);
const atPollerBehavior = createPollerBehavior(maxATPolls, activityTaskPollerBehavior);
return {
namespace: namespace ?? 'default',
identity: `${process.pid}@${os.hostname()}`,
useVersioning: useVersioning ?? false,
buildId,
shutdownGraceTime: 0,
enableNonLocalActivities: true,
workflowTaskPollerBehavior: wftPollerBehavior,
activityTaskPollerBehavior: atPollerBehavior,
stickyQueueScheduleToStartTimeout: '10s',
maxHeartbeatThrottleInterval: '60s',
defaultHeartbeatThrottleInterval: '30s',
// 4294967295ms is the maximum allowed time
isolateExecutionTimeout: debugMode ? '4294967295ms' : '5s',
workflowThreadPoolSize: reuseV8Context ? 1 : 2,
maxCachedWorkflows: maxCachedWorkflows ?? defaultMaxCachedWorkflows,
showStackTraceSources: showStackTraceSources ?? false,
debugMode: debugMode ?? false,
interceptors: {
activity: interceptors?.activity ?? [],
// eslint-disable-next-line deprecation/deprecation
activityInbound: interceptors?.activityInbound ?? [],
workflowModules: interceptors?.workflowModules ?? [],
},
nonStickyToStickyPollRatio: nonStickyToStickyPollRatio ?? 0.2,
sinks: {
...(0, logger_1.initLoggerSink)(logger),
...(0, metrics_1.initMetricSink)(metricMeter),
// Fix deprecated registration of the 'defaultWorkerLogger' sink
...(sinks?.defaultWorkerLogger ? { __temporal_logger: sinks.defaultWorkerLogger } : {}),
...sinks,
},
...rest,
tuner: setTuner,
reuseV8Context,
};
}
function compileWorkerOptions(rawOpts, logger, metricMeter) {
const opts = addDefaultWorkerOptions(rawOpts, logger, metricMeter);
if (opts.maxCachedWorkflows !== 0 && opts.maxCachedWorkflows < 2) {
logger.warn('maxCachedWorkflows must be either 0 (ie. cache is disabled) or greater than 1. Defaulting to 2.');
opts.maxCachedWorkflows = 2;
}
if (opts.maxConcurrentWorkflowTaskExecutions !== undefined) {
if (opts.maxCachedWorkflows > 0 && opts.maxConcurrentWorkflowTaskExecutions > opts.maxCachedWorkflows) {
logger.warn("maxConcurrentWorkflowTaskExecutions can't exceed maxCachedWorkflows (unless cache is disabled). Defaulting to maxCachedWorkflows.");
opts.maxConcurrentWorkflowTaskExecutions = opts.maxCachedWorkflows;
}
if (opts.maxCachedWorkflows > 0 && opts.maxConcurrentWorkflowTaskExecutions < 2) {
logger.warn("maxConcurrentWorkflowTaskExecutions can't be lower than 2 if maxCachedWorkflows is non-zero. Defaulting to 2.");
opts.maxConcurrentWorkflowTaskExecutions = 2;
}
}
const activities = new Map(Object.entries(opts.activities ?? {}).filter(([_, v]) => typeof v === 'function'));
const tuner = (0, worker_tuner_1.asNativeTuner)(opts.tuner, logger);
return {
...opts,
interceptors: compileWorkerInterceptors(opts.interceptors),
shutdownGraceTimeMs: (0, time_1.msToNumber)(opts.shutdownGraceTime),
shutdownForceTimeMs: (0, time_1.msOptionalToNumber)(opts.shutdownForceTime),
stickyQueueScheduleToStartTimeoutMs: (0, time_1.msToNumber)(opts.stickyQueueScheduleToStartTimeout),
isolateExecutionTimeoutMs: (0, time_1.msToNumber)(opts.isolateExecutionTimeout),
maxHeartbeatThrottleIntervalMs: (0, time_1.msToNumber)(opts.maxHeartbeatThrottleInterval),
defaultHeartbeatThrottleIntervalMs: (0, time_1.msToNumber)(opts.defaultHeartbeatThrottleInterval),
loadedDataConverter: (0, internal_non_workflow_1.loadDataConverter)(opts.dataConverter),
activities,
enableNonLocalActivities: opts.enableNonLocalActivities && activities.size > 0,
tuner,
};
}
function toNativeWorkerOptions(opts) {
return {
identity: opts.identity,
buildId: opts.buildId, // eslint-disable-line deprecation/deprecation
useVersioning: opts.useVersioning, // eslint-disable-line deprecation/deprecation
workerDeploymentOptions: toNativeDeploymentOptions(opts.workerDeploymentOptions),
taskQueue: opts.taskQueue,
namespace: opts.namespace,
tuner: opts.tuner,
nonStickyToStickyPollRatio: opts.nonStickyToStickyPollRatio,
workflowTaskPollerBehavior: toNativeTaskPollerBehavior(opts.workflowTaskPollerBehavior),
activityTaskPollerBehavior: toNativeTaskPollerBehavior(opts.activityTaskPollerBehavior),
enableNonLocalActivities: opts.enableNonLocalActivities,
stickyQueueScheduleToStartTimeout: (0, time_1.msToNumber)(opts.stickyQueueScheduleToStartTimeout),
maxCachedWorkflows: opts.maxCachedWorkflows,
maxHeartbeatThrottleInterval: (0, time_1.msToNumber)(opts.maxHeartbeatThrottleInterval),
defaultHeartbeatThrottleInterval: (0, time_1.msToNumber)(opts.defaultHeartbeatThrottleInterval),
maxTaskQueueActivitiesPerSecond: opts.maxTaskQueueActivitiesPerSecond ?? null,
maxActivitiesPerSecond: opts.maxActivitiesPerSecond ?? null,
shutdownGraceTime: (0, time_1.msToNumber)(opts.shutdownGraceTime),
};
}
function toNativeTaskPollerBehavior(behavior) {
switch (behavior.type) {
case 'simple-maximum':
return {
type: 'simple-maximum',
maximum: behavior.maximum,
};
case 'autoscaling':
return {
type: 'autoscaling',
minimum: behavior.minimum,
initial: behavior.initial,
maximum: behavior.maximum,
};
default:
throw new Error(`Unknown poller behavior type: ${behavior.type}`);
}
}
function toNativeDeploymentOptions(options) {
if (options === undefined) {
return null;
}
let vb;
switch (options.defaultVersioningBehavior) {
case 'PINNED':
vb = { type: 'pinned' };
break;
case 'AUTO_UPGRADE':
vb = { type: 'auto-upgrade' };
break;
default:
options.defaultVersioningBehavior;
throw new Error(`Unknown versioning behavior: ${options.defaultVersioningBehavior}`);
}
return {
version: options.version,
useWorkerVersioning: options.useWorkerVersioning,
defaultVersioningBehavior: vb,
};
}
// Utils ///////////////////////////////////////////////////////////////////////////////////////////
function isSet(env) {
if (env === undefined)
return false;
env = env.toLocaleLowerCase();
return env === '1' || env === 't' || env === 'true';
}
//# sourceMappingURL=worker-options.js.map
;