@temporalio/workflow
Version:
Temporal.io SDK Workflow sub-package
96 lines • 4.23 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.overrideGlobals = overrideGlobals;
/**
* Overrides some global objects to make them deterministic.
*
* @module
*/
const time_1 = require("@temporalio/common/lib/time");
const cancellation_scope_1 = require("./cancellation-scope");
const errors_1 = require("./errors");
const global_attributes_1 = require("./global-attributes");
const flags_1 = require("./flags");
const workflow_1 = require("./workflow");
const stack_helpers_1 = require("./stack-helpers");
const global = globalThis;
const OriginalDate = globalThis.Date;
function overrideGlobals() {
// Mock any weak reference because GC is non-deterministic and the effect is observable from the Workflow.
// Workflow developer will get a meaningful exception if they try to use these.
global.WeakRef = function () {
throw new errors_1.DeterminismViolationError('WeakRef cannot be used in Workflows because v8 GC is non-deterministic');
};
global.FinalizationRegistry = function () {
throw new errors_1.DeterminismViolationError('FinalizationRegistry cannot be used in Workflows because v8 GC is non-deterministic');
};
global.Date = function (...args) {
if (args.length > 0) {
return new OriginalDate(...args);
}
return new OriginalDate((0, global_attributes_1.getActivator)().now);
};
global.Date.now = function () {
return (0, global_attributes_1.getActivator)().now;
};
global.Date.parse = OriginalDate.parse.bind(OriginalDate);
global.Date.UTC = OriginalDate.UTC.bind(OriginalDate);
global.Date.prototype = OriginalDate.prototype;
const timeoutCancelationScopes = new Map();
/**
* @param ms sleep duration - number of milliseconds. If given a negative number, value will be set to 1.
*/
global.setTimeout = function (cb, ms, ...args) {
ms = Math.max(1, ms);
const activator = (0, global_attributes_1.getActivator)();
if (activator.hasFlag(flags_1.SdkFlags.NonCancellableScopesAreShieldedFromPropagation)) {
// Capture the sequence number that sleep will allocate
const seq = activator.nextSeqs.timer;
const timerScope = new cancellation_scope_1.CancellationScope({ cancellable: true });
const sleepPromise = timerScope.run(() => (0, workflow_1.sleep)(ms));
sleepPromise.then(() => {
timeoutCancelationScopes.delete(seq);
cb(...args);
}, () => {
timeoutCancelationScopes.delete(seq);
});
(0, stack_helpers_1.untrackPromise)(sleepPromise);
timeoutCancelationScopes.set(seq, timerScope);
return seq;
}
else {
const seq = activator.nextSeqs.timer++;
// Create a Promise for AsyncLocalStorage to be able to track this completion using promise hooks.
new Promise((resolve, reject) => {
activator.completions.timer.set(seq, { resolve, reject });
activator.pushCommand({
startTimer: {
seq,
startToFireTimeout: (0, time_1.msToTs)(ms),
},
});
}).then(() => cb(...args), () => undefined /* ignore cancellation */);
return seq;
}
};
global.clearTimeout = function (handle) {
const activator = (0, global_attributes_1.getActivator)();
const timerScope = timeoutCancelationScopes.get(handle);
if (timerScope) {
timeoutCancelationScopes.delete(handle);
timerScope.cancel();
}
else {
activator.nextSeqs.timer++; // Shouldn't increase seq number, but that's the legacy behavior
activator.completions.timer.delete(handle);
activator.pushCommand({
cancelTimer: {
seq: handle,
},
});
}
};
// activator.random is mutable, don't hardcode its reference
Math.random = () => (0, global_attributes_1.getActivator)().random();
}
//# sourceMappingURL=global-overrides.js.map
;