Skip to content

Evolve sandbox documentation #907

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 22, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 15 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -946,19 +946,12 @@ workflow will not progress until fixed.
The sandbox is not foolproof and non-determinism can still occur. It is simply a best-effort way to catch bad code
early. Users are encouraged to define their workflows in files with no other side effects.

The sandbox offers a mechanism to pass through modules from outside the sandbox. By default this already includes all
The sandbox offers a mechanism to "pass through" modules from outside the sandbox. By default this already includes all
standard library modules and Temporal modules. **For performance and behavior reasons, users are encouraged to pass
through all third party modules whose calls will be deterministic.** This includes modules containing the activities to
be referenced in workflows. See "Passthrough Modules" below on how to do this.
through all modules whose calls will be deterministic.** In particular, this advice extends to modules containing the
activities to be referenced in workflows, and modules containing dataclasses and Pydantic models, which can be
particularly expensive to import. See "Passthrough Modules" below on how to do this.

If you are getting an error like:

> temporalio.worker.workflow_sandbox._restrictions.RestrictedWorkflowAccessError: Cannot access
> http.client.IncompleteRead.\_\_mro_entries\_\_ from inside a workflow. If this is code from a module not used in a
> workflow or known to only be used deterministically from a workflow, mark the import as pass through.

Then you are either using an invalid construct from the workflow, this is a known limitation of the sandbox, or most
commonly this is from a module that is safe to pass through (see "Passthrough Modules" section below).

##### How the Sandbox Works

Expand All @@ -967,12 +960,13 @@ The sandbox is made up of two components that work closely together:
* Global state isolation
* Restrictions preventing known non-deterministic library calls

Global state isolation is performed by using `exec`. Upon workflow start, the file that the workflow is defined in is
imported into a new sandbox created for that workflow run. In order to keep the sandbox performant a known set of
"passthrough modules" are passed through from outside of the sandbox when they are imported. These are expected to be
side-effect free on import and have their non-deterministic aspects restricted. By default the entire Python standard
library, `temporalio`, and a couple of other modules are passed through from outside of the sandbox. To update this
list, see "Customizing the Sandbox".
Global state isolation is performed by using `exec`. Upon workflow start, and every time that the workflow is replayed,
the file that the workflow is defined in is re-imported into a new sandbox created for that workflow run. In order to
keep the sandbox performant, not all modules are re-imported in this way: instead, a known set of "passthrough modules"
are obtained as references to the already-imported module _outside_ the sandbox. These modules should be side-effect
free on import and, if they make any non-deterministic calls, then these should be restricted by sandbox restriction
rules. By default the entire Python standard library, `temporalio`, and a couple of other modules are "passed through"
in this way from outside of the sandbox. To update this list, see "Customizing the Sandbox".

Restrictions preventing known non-deterministic library calls are achieved using proxy objects on modules wrapped around
the custom importer set in the sandbox. Many restrictions apply at workflow import time and workflow run time, while
Expand All @@ -984,7 +978,7 @@ and isn't restricted, see "Customizing the Sandbox".
##### Avoiding the Sandbox

There are three increasingly-scoped ways to avoid the sandbox. Users are discouraged from avoiding the sandbox if
possible.
possible, except for passing through safe modules, which is recommended.

To remove restrictions around a particular block of code, use `with temporalio.workflow.unsafe.sandbox_unrestricted():`.
The workflow will still be running in the sandbox, but no restrictions for invalid library calls will be applied.
Expand All @@ -1011,11 +1005,12 @@ is immutable and contains three fields that can be customized, but only two have
###### Passthrough Modules

By default the sandbox completely reloads non-standard-library and non-Temporal modules for every workflow run. To make
the sandbox quicker and use less memory when importing known-side-effect-free third party modules, they can be marked
the sandbox quicker and use less memory when importing known-side-effect-free modules, they can be marked
as passthrough modules.

**For performance and behavior reasons, users are encouraged to pass through all third party modules whose calls will be
deterministic.**
deterministic.** In particular, this advice extends to modules containing the activities to be referenced in workflows,
and modules containing dataclasses and Pydantic models, which can be particularly expensive to import.

One way to pass through a module is at import time in the workflow file using the `imports_passed_through` context
manager like so:
Expand Down
Loading