Skip to content

Commit 1a2aca2

Browse files
authored
Evolve sandbox documentation (#907)
Improve sandbox documentation, in particular relating to dataclasses and Pydantic models as a result of discussion in https://temporalio.slack.com/archives/CTT84RS0P/p1749927322488079.
1 parent 3e2500c commit 1a2aca2

File tree

1 file changed

+15
-20
lines changed

1 file changed

+15
-20
lines changed

README.md

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -946,19 +946,12 @@ workflow will not progress until fixed.
946946
The sandbox is not foolproof and non-determinism can still occur. It is simply a best-effort way to catch bad code
947947
early. Users are encouraged to define their workflows in files with no other side effects.
948948

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

954-
If you are getting an error like:
955-
956-
> temporalio.worker.workflow_sandbox._restrictions.RestrictedWorkflowAccessError: Cannot access
957-
> http.client.IncompleteRead.\_\_mro_entries\_\_ from inside a workflow. If this is code from a module not used in a
958-
> workflow or known to only be used deterministically from a workflow, mark the import as pass through.
959-
960-
Then you are either using an invalid construct from the workflow, this is a known limitation of the sandbox, or most
961-
commonly this is from a module that is safe to pass through (see "Passthrough Modules" section below).
962955

963956
##### How the Sandbox Works
964957

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

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)