|
7 | 7 | import threading |
8 | 8 | import traceback |
9 | 9 | from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple |
| 10 | +from uuid import uuid4 |
10 | 11 |
|
11 | 12 | from ldclient.config import Config |
12 | 13 | from ldclient.context import Context |
@@ -188,15 +189,43 @@ def __init__(self, config: Config, start_wait: float = 5): |
188 | 189 | check_uwsgi() |
189 | 190 |
|
190 | 191 | self._config = config |
| 192 | + self._config._instance_id = str(uuid4()) |
191 | 193 | self._config._validate() |
192 | 194 |
|
193 | | - self.__hooks_lock = ReadWriteLock() |
194 | | - self.__hooks = config.hooks # type: List[Hook] |
195 | | - |
196 | 195 | self._event_processor = None |
197 | 196 | self._event_factory_default = EventFactory(False) |
198 | 197 | self._event_factory_with_reasons = EventFactory(True) |
199 | 198 |
|
| 199 | + self.__start_up(start_wait) |
| 200 | + |
| 201 | + def postfork(self, start_wait: float = 5): |
| 202 | + """ |
| 203 | + Re-initializes an existing client after a process fork. |
| 204 | +
|
| 205 | + The SDK relies on multiple background threads to operate correctly. |
| 206 | + When a process forks, `these threads are not available to the child |
| 207 | + <https://pythondev.readthedocs.io/fork.html#reinitialize-all-locks-after-fork>`. |
| 208 | +
|
| 209 | + As a result, the SDK will not function correctly in the child process |
| 210 | + until it is re-initialized. |
| 211 | +
|
| 212 | + This method is effectively equivalent to instantiating a new client. |
| 213 | + Future iterations of the SDK will provide increasingly efficient |
| 214 | + re-initializing improvements. |
| 215 | +
|
| 216 | + Note that any configuration provided to the SDK will need to survive |
| 217 | + the forking process independently. For this reason, it is recommended |
| 218 | + that any listener or hook integrations be added postfork unless you are |
| 219 | + certain it can survive the forking process. |
| 220 | +
|
| 221 | + :param start_wait: the number of seconds to wait for a successful connection to LaunchDarkly |
| 222 | + """ |
| 223 | + self.__start_up(start_wait) |
| 224 | + |
| 225 | + def __start_up(self, start_wait: float): |
| 226 | + self.__hooks_lock = ReadWriteLock() |
| 227 | + self.__hooks = self._config.hooks # type: List[Hook] |
| 228 | + |
200 | 229 | data_store_listeners = Listeners() |
201 | 230 | store_sink = DataStoreUpdateSinkImpl(data_store_listeners) |
202 | 231 | store = _FeatureStoreClientWrapper(self._config.feature_store, store_sink) |
|
0 commit comments