feat(workflow): add nondeterministic random API to UnsafeWorkflowInfo#2133
feat(workflow): add nondeterministic random API to UnsafeWorkflowInfo#2133brucearctor wants to merge 1 commit into
Conversation
Adds unsafe.random() to workflowInfo().unsafe, providing a nondeterministic source of randomness for use in query handlers and interceptors where deterministic replay is not required (e.g. generating unique trace IDs for observability and telemetry). The implementation captures the real Math.random before the workflow sandbox overrides it, following the same pattern used for unsafe.now (which captures OriginalDate.now). Note: This is the first Temporal SDK to expose unsafe nondeterministic random. Go/Java SDKs rely on SideEffect() for nondeterminism, but SideEffect cannot be used in query handlers (which can't produce commands). This API fills a TypeScript-specific gap caused by the workflow sandbox replacing Math.random with a deterministic PRNG. Closes temporalio#2110
|
Apologies that the original issue #2110 didn't got into clear detail about the desired interface, but we need the unsafe random interface to mirror the new named one e.g. being able to generate UUIDs/fill buffers. #2141 was also opened by a team member and will be the PR we go with for resolving this issue. We appreciate your contributions and sorry for the mixup. |
|
Thanks for the message. Community management is hard, what is in public, and putting enough detail in tickets/etc -- esp. balancing open contributions and those on payroll [ latter more easy to jump on a call with ]. I do hope we can improve process. Ex: so I can ensure to not spending time on PRs that are undesired. Second time this week [ other was in sdk-java ]. Def happy to understand what i can be doing differently [ ideally in a way that doesn't add much more friction to contributing, as a volunteer ]. |
Summary
Adds
workflowInfo().unsafe.random()— a nondeterministic random number generator exposed onUnsafeWorkflowInfo, for use in query handlers, update validators, interceptors, and sinks where deterministic replay is not required.Primary use case: generating unique trace/correlation IDs for observability and telemetry in query handlers (as requested in #2110).
Motivation
The workflow sandbox replaces
Math.random()with a deterministic PRNG seeded from the workflow seed. This is essential for replay correctness, but makes it impossible for query handlers and interceptors to generate truly unique identifiers for observability purposes.SideEffect()cannot be used in query handlers since they cannot produce commands.Implementation
Follows the exact same pattern as the existing
unsafe.now():Math.randomat module load time inworker-interface.ts(beforeoverrideGlobals()replaces it with the deterministic PRNG)unsafe.randomduringinitRuntime()unsafe.now)Changes
Core (3 files)
packages/workflow/src/interfaces.ts— Addedrandom: () => numbertoUnsafeWorkflowInfowith comprehensive JSDoc (@experimental)packages/workflow/src/worker-interface.ts— CapturedOriginalMathRandombefore sandbox overridespackages/worker/src/worker.ts— Addedrandom: Math.randomto initial unsafe objectThread serialization (2 files)
packages/worker/src/workflow/threaded-vm.ts— Delete before thread send; restore after sink call deserializationpackages/worker/src/workflow/workflow-worker-thread.ts— Delete before sink call serializationTests (6 files)
unsafe-random.ts) with bothunsafeRandomanddeterministicRandomquery handlersUnsafeWorkflowInfoAPI
Safe to use in: query handlers, update validators, interceptors, sinks.
NOT safe in: main workflow function, signal handlers, update handlers (breaks replay).
Testing
test-workflows.jspassunsafeRandomtest validates nondeterminism and source independenceCloses #2110