2424import temporalio .bridge .runtime
2525import temporalio .common
2626
27- _default_runtime : Optional [Runtime ] = None
27+
28+ class _RuntimeRef :
29+ def __init__ (
30+ self ,
31+ ) -> None :
32+ self ._default_runtime : Runtime | None = None
33+ self ._prevent_default = False
34+
35+ def default (self ) -> Runtime :
36+ if not self ._default_runtime :
37+ if self ._prevent_default :
38+ raise RuntimeError (
39+ "Cannot create default Runtime after Runtime.prevent_default has been called"
40+ )
41+ self ._default_runtime = Runtime (telemetry = TelemetryConfig ())
42+ self ._default_created = True
43+ return self ._default_runtime
44+
45+ def prevent_default (self ):
46+ if self ._default_runtime :
47+ raise RuntimeError (
48+ "Runtime.prevent_default called after default runtime has been created or set"
49+ )
50+ self ._prevent_default = True
51+
52+ def set_default (
53+ self , runtime : Runtime , * , error_if_already_set : bool = True
54+ ) -> None :
55+ if self ._default_runtime and error_if_already_set :
56+ raise RuntimeError ("Runtime default already set" )
57+
58+ self ._default_runtime = runtime
59+
60+
61+ _runtime_ref : _RuntimeRef = _RuntimeRef ()
2862
2963
3064class Runtime :
3165 """Runtime for Temporal Python SDK.
3266
33- Users are encouraged to use :py:meth:`default`. It can be set with
67+ Most users are encouraged to use :py:meth:`default`. It can be set with
3468 :py:meth:`set_default`. Every time a new runtime is created, a new internal
3569 thread pool is created.
3670
37- Runtimes do not work across forks.
71+ Runtimes do not work across forks. Advanced users should consider using
72+ :py:meth:`prevent_default` and `:py:meth`set_default` to ensure each
73+ fork creates it's own runtime.
74+
3875 """
3976
4077 @classmethod
4178 def default (cls ) -> Runtime :
42- """Get the default runtime, creating if not already created.
79+ """Get the default runtime, creating if not already created. If :py:meth:`prevent_default`
80+ is called before this method it will raise a RuntimeError instead of creating a default
81+ runtime.
4382
4483 If the default runtime needs to be different, it should be done with
4584 :py:meth:`set_default` before this is called or ever used.
4685
4786 Returns:
4887 The default runtime.
4988 """
50- global _default_runtime
51- if not _default_runtime :
52- _default_runtime = cls (telemetry = TelemetryConfig ())
53- return _default_runtime
89+ global _runtime_ref
90+ return _runtime_ref .default ()
91+
92+ @classmethod
93+ def prevent_default (cls ):
94+ """Prevent :py:meth:`default` from lazily creating a :py:class:`Runtime`.
95+
96+ Raises a RuntimeError if a default :py:class:`Runtime` has already been created.
97+
98+ Explicitly setting a default runtime with :py:meth:`set_default` bypasses this setting and
99+ future calls to :py:meth:`default` will return the provided runtime.
100+ """
101+ global _runtime_ref
102+ _runtime_ref .prevent_default ()
54103
55104 @staticmethod
56105 def set_default (runtime : Runtime , * , error_if_already_set : bool = True ) -> None :
@@ -65,10 +114,8 @@ def set_default(runtime: Runtime, *, error_if_already_set: bool = True) -> None:
65114 error_if_already_set: If True and default is already set, this will
66115 raise a RuntimeError.
67116 """
68- global _default_runtime
69- if _default_runtime and error_if_already_set :
70- raise RuntimeError ("Runtime default already set" )
71- _default_runtime = runtime
117+ global _runtime_ref
118+ _runtime_ref .set_default (runtime , error_if_already_set = error_if_already_set )
72119
73120 def __init__ (
74121 self ,
0 commit comments