UNPKG

@temporalio/workflow

Version:
96 lines 4.23 kB
"use strict"; 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