dbos 0.26.0a13__py3-none-any.whl → 0.26.0a14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dbos/_core.py +3 -1
- dbos/_dbos.py +4 -2
- dbos/_event_loop.py +67 -0
- {dbos-0.26.0a13.dist-info → dbos-0.26.0a14.dist-info}/METADATA +1 -1
- {dbos-0.26.0a13.dist-info → dbos-0.26.0a14.dist-info}/RECORD +8 -7
- {dbos-0.26.0a13.dist-info → dbos-0.26.0a14.dist-info}/WHEEL +0 -0
- {dbos-0.26.0a13.dist-info → dbos-0.26.0a14.dist-info}/entry_points.txt +0 -0
- {dbos-0.26.0a13.dist-info → dbos-0.26.0a14.dist-info}/licenses/LICENSE +0 -0
dbos/_core.py
CHANGED
@@ -365,7 +365,9 @@ def _execute_workflow_wthread(
|
|
365
365
|
if isinstance(result, Immediate):
|
366
366
|
return cast(Immediate[R], result)()
|
367
367
|
else:
|
368
|
-
return
|
368
|
+
return dbos._background_event_loop.submit_coroutine(
|
369
|
+
cast(Pending[R], result)()
|
370
|
+
)
|
369
371
|
except Exception:
|
370
372
|
dbos.logger.error(
|
371
373
|
f"Exception encountered in asynchronous workflow: {traceback.format_exc()}"
|
dbos/_dbos.py
CHANGED
@@ -4,7 +4,6 @@ import asyncio
|
|
4
4
|
import atexit
|
5
5
|
import hashlib
|
6
6
|
import inspect
|
7
|
-
import json
|
8
7
|
import os
|
9
8
|
import sys
|
10
9
|
import threading
|
@@ -31,7 +30,6 @@ from typing import (
|
|
31
30
|
|
32
31
|
from opentelemetry.trace import Span
|
33
32
|
|
34
|
-
from dbos import _serialization
|
35
33
|
from dbos._conductor.conductor import ConductorWebsocket
|
36
34
|
from dbos._utils import INTERNAL_QUEUE_NAME, GlobalParams
|
37
35
|
from dbos._workflow_commands import (
|
@@ -112,6 +110,7 @@ from ._error import (
|
|
112
110
|
DBOSException,
|
113
111
|
DBOSNonExistentWorkflowError,
|
114
112
|
)
|
113
|
+
from ._event_loop import BackgroundEventLoop
|
115
114
|
from ._logger import add_otlp_to_all_loggers, config_logger, dbos_logger, init_logger
|
116
115
|
from ._sys_db import SystemDatabase
|
117
116
|
from ._workflow_commands import WorkflowStatus, get_workflow
|
@@ -341,6 +340,7 @@ class DBOS:
|
|
341
340
|
self.conductor_url: Optional[str] = conductor_url
|
342
341
|
self.conductor_key: Optional[str] = conductor_key
|
343
342
|
self.conductor_websocket: Optional[ConductorWebsocket] = None
|
343
|
+
self._background_event_loop: BackgroundEventLoop = BackgroundEventLoop()
|
344
344
|
|
345
345
|
init_logger()
|
346
346
|
|
@@ -451,6 +451,7 @@ class DBOS:
|
|
451
451
|
dbos_logger.info(f"Executor ID: {GlobalParams.executor_id}")
|
452
452
|
dbos_logger.info(f"Application version: {GlobalParams.app_version}")
|
453
453
|
self._executor_field = ThreadPoolExecutor(max_workers=64)
|
454
|
+
self._background_event_loop.start()
|
454
455
|
self._sys_db_field = SystemDatabase(
|
455
456
|
self.config["database"], debug_mode=debug_mode
|
456
457
|
)
|
@@ -568,6 +569,7 @@ class DBOS:
|
|
568
569
|
self._initialized = False
|
569
570
|
for event in self.stop_events:
|
570
571
|
event.set()
|
572
|
+
self._background_event_loop.stop()
|
571
573
|
if self._sys_db_field is not None:
|
572
574
|
self._sys_db_field.destroy()
|
573
575
|
self._sys_db_field = None
|
dbos/_event_loop.py
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
import asyncio
|
2
|
+
import threading
|
3
|
+
from typing import Any, Coroutine, Optional, TypeVar
|
4
|
+
|
5
|
+
|
6
|
+
class BackgroundEventLoop:
|
7
|
+
"""
|
8
|
+
This is the event loop to which DBOS submits any coroutines that are not started from within an event loop.
|
9
|
+
In particular, coroutines submitted to queues (such as from scheduled workflows) run on this event loop.
|
10
|
+
"""
|
11
|
+
|
12
|
+
def __init__(self) -> None:
|
13
|
+
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
14
|
+
self._thread: Optional[threading.Thread] = None
|
15
|
+
self._running = False
|
16
|
+
self._ready = threading.Event()
|
17
|
+
|
18
|
+
def start(self) -> None:
|
19
|
+
if self._running:
|
20
|
+
return
|
21
|
+
|
22
|
+
self._thread = threading.Thread(target=self._run_event_loop, daemon=True)
|
23
|
+
self._thread.start()
|
24
|
+
self._ready.wait() # Wait until the loop is running
|
25
|
+
|
26
|
+
def stop(self) -> None:
|
27
|
+
if not self._running or self._loop is None or self._thread is None:
|
28
|
+
return
|
29
|
+
|
30
|
+
asyncio.run_coroutine_threadsafe(self._shutdown(), self._loop)
|
31
|
+
self._thread.join()
|
32
|
+
self._running = False
|
33
|
+
|
34
|
+
def _run_event_loop(self) -> None:
|
35
|
+
self._loop = asyncio.new_event_loop()
|
36
|
+
asyncio.set_event_loop(self._loop)
|
37
|
+
|
38
|
+
self._running = True
|
39
|
+
self._ready.set() # Signal that the loop is ready
|
40
|
+
|
41
|
+
try:
|
42
|
+
self._loop.run_forever()
|
43
|
+
finally:
|
44
|
+
self._loop.close()
|
45
|
+
|
46
|
+
async def _shutdown(self) -> None:
|
47
|
+
if self._loop is None:
|
48
|
+
raise RuntimeError("Event loop not started")
|
49
|
+
tasks = [
|
50
|
+
task
|
51
|
+
for task in asyncio.all_tasks(self._loop)
|
52
|
+
if task is not asyncio.current_task(self._loop)
|
53
|
+
]
|
54
|
+
|
55
|
+
for task in tasks:
|
56
|
+
task.cancel()
|
57
|
+
|
58
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
59
|
+
self._loop.stop()
|
60
|
+
|
61
|
+
T = TypeVar("T")
|
62
|
+
|
63
|
+
def submit_coroutine(self, coro: Coroutine[Any, Any, T]) -> T:
|
64
|
+
"""Submit a coroutine to the background event loop"""
|
65
|
+
if self._loop is None:
|
66
|
+
raise RuntimeError("Event loop not started")
|
67
|
+
return asyncio.run_coroutine_threadsafe(coro, self._loop).result()
|
@@ -1,7 +1,7 @@
|
|
1
|
-
dbos-0.26.
|
2
|
-
dbos-0.26.
|
3
|
-
dbos-0.26.
|
4
|
-
dbos-0.26.
|
1
|
+
dbos-0.26.0a14.dist-info/METADATA,sha256=KmqNCgW2bcxs1qddgonsP0MDPe1tt5tlUvs07bN-XDY,5554
|
2
|
+
dbos-0.26.0a14.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
|
3
|
+
dbos-0.26.0a14.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
|
4
|
+
dbos-0.26.0a14.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
|
5
5
|
dbos/__init__.py,sha256=3NQfGlBiiUSM_v88STdVP3rNZvGkUL_9WbSotKb8Voo,873
|
6
6
|
dbos/__main__.py,sha256=G7Exn-MhGrVJVDbgNlpzhfh8WMX_72t3_oJaFT9Lmt8,653
|
7
7
|
dbos/_admin_server.py,sha256=vxPG_YJ6lYrkfPCSp42FiATVLBOij7Fm52Yngg5Z_tE,7027
|
@@ -11,13 +11,14 @@ dbos/_client.py,sha256=5iaoFsu5wAqwjjj3EWusZ1eDbBAW8FwYazhokdCJ9h4,10964
|
|
11
11
|
dbos/_conductor/conductor.py,sha256=HYzVL29IMMrs2Mnms_7cHJynCnmmEN5SDQOMjzn3UoU,16840
|
12
12
|
dbos/_conductor/protocol.py,sha256=xN7pmooyF1pqbH1b6WhllU5718P7zSb_b0KCwA6bzcs,6716
|
13
13
|
dbos/_context.py,sha256=I8sLkdKTTkZEz7wG-MjynaQB6XEF2bLXuwNksiauP7w,19430
|
14
|
-
dbos/_core.py,sha256=
|
14
|
+
dbos/_core.py,sha256=de8GecFmW5DNf5dYfnpSX3IDO24Wc6pBpCC1VZ1iVyI,45505
|
15
15
|
dbos/_croniter.py,sha256=XHAyUyibs_59sJQfSNWkP7rqQY6_XrlfuuCxk4jYqek,47559
|
16
|
-
dbos/_dbos.py,sha256=
|
16
|
+
dbos/_dbos.py,sha256=byXhhiG14nS3iU85NphvQ26vvnJ-gu1tMwTIoUc3dYc,46239
|
17
17
|
dbos/_dbos_config.py,sha256=m05IFjM0jSwZBsnFMF_4qP2JkjVFc0gqyM2tnotXq20,20636
|
18
18
|
dbos/_debug.py,sha256=MNlQVZ6TscGCRQeEEL0VE8Uignvr6dPeDDDefS3xgIE,1823
|
19
19
|
dbos/_docker_pg_helper.py,sha256=NmcgqmR5rQA_4igfeqh8ugNT2z3YmoOvuep_MEtxTiY,5854
|
20
20
|
dbos/_error.py,sha256=9ITvFsN_Udpx0xXtYQHXXXb6PjPr3TmMondGmprV-L0,7003
|
21
|
+
dbos/_event_loop.py,sha256=NmaLbEQFfEK36S_0KhVD39YdYrGce3qSKCTJ-5RqKQ0,2136
|
21
22
|
dbos/_fastapi.py,sha256=PhaKftbApHnjtYEOw0EYna_3K0cmz__J9of7mRJWzu4,3704
|
22
23
|
dbos/_flask.py,sha256=DZKUZR5-xOzPI7tYZ53r2PvvHVoAb8SYwLzMVFsVfjI,2608
|
23
24
|
dbos/_kafka.py,sha256=pz0xZ9F3X9Ky1k-VSbeF3tfPhP3UPr3lUUhUfE41__U,4198
|
@@ -64,4 +65,4 @@ dbos/cli/cli.py,sha256=Lb_RYmXoT5KH0xDbwaYpROE4c-svZ0eCq2Kxg7cAxTw,16537
|
|
64
65
|
dbos/dbos-config.schema.json,sha256=i7jcxXqByKq0Jzv3nAUavONtj03vTwj6vWP4ylmBr8o,5694
|
65
66
|
dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
|
66
67
|
version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
|
67
|
-
dbos-0.26.
|
68
|
+
dbos-0.26.0a14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|