dbos 0.16.0a2__py3-none-any.whl → 0.17.0__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.
Potentially problematic release.
This version of dbos might be problematic. Click here for more details.
- dbos/_core.py +3 -3
- dbos/_dbos.py +3 -2
- dbos/_outcome.py +23 -7
- dbos/_queue.py +2 -2
- dbos/_sys_db.py +6 -3
- {dbos-0.16.0a2.dist-info → dbos-0.17.0.dist-info}/METADATA +1 -1
- {dbos-0.16.0a2.dist-info → dbos-0.17.0.dist-info}/RECORD +10 -10
- {dbos-0.16.0a2.dist-info → dbos-0.17.0.dist-info}/WHEEL +0 -0
- {dbos-0.16.0a2.dist-info → dbos-0.17.0.dist-info}/entry_points.txt +0 -0
- {dbos-0.16.0a2.dist-info → dbos-0.17.0.dist-info}/licenses/LICENSE +0 -0
dbos/_core.py
CHANGED
|
@@ -21,7 +21,7 @@ from typing import (
|
|
|
21
21
|
overload,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
from dbos._outcome import Immediate, Outcome, Pending
|
|
24
|
+
from dbos._outcome import Immediate, NoResult, Outcome, Pending
|
|
25
25
|
|
|
26
26
|
from ._app_db import ApplicationDatabase, TransactionResultInternal
|
|
27
27
|
|
|
@@ -719,7 +719,7 @@ def decorate_step(
|
|
|
719
719
|
finally:
|
|
720
720
|
dbos._sys_db.record_operation_result(step_output)
|
|
721
721
|
|
|
722
|
-
def check_existing_result() ->
|
|
722
|
+
def check_existing_result() -> Union[NoResult, R]:
|
|
723
723
|
ctx = assert_current_dbos_context()
|
|
724
724
|
recorded_output = dbos._sys_db.check_operation_execution(
|
|
725
725
|
ctx.workflow_id, ctx.function_id
|
|
@@ -743,7 +743,7 @@ def decorate_step(
|
|
|
743
743
|
dbos.logger.debug(
|
|
744
744
|
f"Running step, id: {ctx.function_id}, name: {attributes['name']}"
|
|
745
745
|
)
|
|
746
|
-
return
|
|
746
|
+
return NoResult()
|
|
747
747
|
|
|
748
748
|
stepOutcome = Outcome[R].make(functools.partial(func, *args, **kwargs))
|
|
749
749
|
if retries_allowed:
|
dbos/_dbos.py
CHANGED
|
@@ -45,7 +45,7 @@ from ._core import (
|
|
|
45
45
|
start_workflow,
|
|
46
46
|
workflow_wrapper,
|
|
47
47
|
)
|
|
48
|
-
from ._queue import Queue,
|
|
48
|
+
from ._queue import Queue, queue_thread
|
|
49
49
|
from ._recovery import recover_pending_workflows, startup_recovery_thread
|
|
50
50
|
from ._registrations import (
|
|
51
51
|
DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
|
@@ -283,6 +283,7 @@ class DBOS:
|
|
|
283
283
|
self.flask: Optional["Flask"] = flask
|
|
284
284
|
self._executor_field: Optional[ThreadPoolExecutor] = None
|
|
285
285
|
self._background_threads: List[threading.Thread] = []
|
|
286
|
+
self._executor_id: str = os.environ.get("DBOS__VMID", "local")
|
|
286
287
|
|
|
287
288
|
# If using FastAPI, set up middleware and lifecycle events
|
|
288
289
|
if self.fastapi is not None:
|
|
@@ -383,7 +384,7 @@ class DBOS:
|
|
|
383
384
|
evt = threading.Event()
|
|
384
385
|
self.stop_events.append(evt)
|
|
385
386
|
bg_queue_thread = threading.Thread(
|
|
386
|
-
target=
|
|
387
|
+
target=queue_thread, args=(evt, self), daemon=True
|
|
387
388
|
)
|
|
388
389
|
bg_queue_thread.start()
|
|
389
390
|
self._background_threads.append(bg_queue_thread)
|
dbos/_outcome.py
CHANGED
|
@@ -8,6 +8,16 @@ T = TypeVar("T")
|
|
|
8
8
|
R = TypeVar("R")
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
class NoResult:
|
|
12
|
+
_instance: Optional["NoResult"] = None
|
|
13
|
+
__slots__ = ()
|
|
14
|
+
|
|
15
|
+
def __new__(cls, *args: Any, **kwargs: Any) -> "NoResult":
|
|
16
|
+
if not cls._instance:
|
|
17
|
+
cls._instance = super(NoResult, cls).__new__(cls, *args, **kwargs)
|
|
18
|
+
return cls._instance
|
|
19
|
+
|
|
20
|
+
|
|
11
21
|
# define Outcome protocol w/ common composition methods
|
|
12
22
|
class Outcome(Protocol[T]):
|
|
13
23
|
|
|
@@ -28,7 +38,9 @@ class Outcome(Protocol[T]):
|
|
|
28
38
|
exceeded_retries: Callable[[int], BaseException],
|
|
29
39
|
) -> "Outcome[T]": ...
|
|
30
40
|
|
|
31
|
-
def intercept(
|
|
41
|
+
def intercept(
|
|
42
|
+
self, interceptor: Callable[[], Union[NoResult, T]]
|
|
43
|
+
) -> "Outcome[T]": ...
|
|
32
44
|
|
|
33
45
|
def __call__(self) -> Union[T, Coroutine[Any, Any, T]]: ...
|
|
34
46
|
|
|
@@ -58,11 +70,15 @@ class Immediate(Outcome[T]):
|
|
|
58
70
|
return Immediate(lambda: before()(self._func))
|
|
59
71
|
|
|
60
72
|
@staticmethod
|
|
61
|
-
def _intercept(
|
|
73
|
+
def _intercept(
|
|
74
|
+
func: Callable[[], T], interceptor: Callable[[], Union[NoResult, T]]
|
|
75
|
+
) -> T:
|
|
62
76
|
intercepted = interceptor()
|
|
63
|
-
return intercepted if intercepted else func()
|
|
77
|
+
return intercepted if not isinstance(intercepted, NoResult) else func()
|
|
64
78
|
|
|
65
|
-
def intercept(
|
|
79
|
+
def intercept(
|
|
80
|
+
self, interceptor: Callable[[], Union[NoResult, T]]
|
|
81
|
+
) -> "Immediate[T]":
|
|
66
82
|
return Immediate[T](lambda: Immediate._intercept(self._func, interceptor))
|
|
67
83
|
|
|
68
84
|
@staticmethod
|
|
@@ -151,12 +167,12 @@ class Pending(Outcome[T]):
|
|
|
151
167
|
@staticmethod
|
|
152
168
|
async def _intercept(
|
|
153
169
|
func: Callable[[], Coroutine[Any, Any, T]],
|
|
154
|
-
interceptor: Callable[[],
|
|
170
|
+
interceptor: Callable[[], Union[NoResult, T]],
|
|
155
171
|
) -> T:
|
|
156
172
|
intercepted = await asyncio.to_thread(interceptor)
|
|
157
|
-
return intercepted if intercepted else await func()
|
|
173
|
+
return intercepted if not isinstance(intercepted, NoResult) else await func()
|
|
158
174
|
|
|
159
|
-
def intercept(self, interceptor: Callable[[],
|
|
175
|
+
def intercept(self, interceptor: Callable[[], Union[NoResult, T]]) -> "Pending[T]":
|
|
160
176
|
return Pending[T](lambda: Pending._intercept(self._func, interceptor))
|
|
161
177
|
|
|
162
178
|
@staticmethod
|
dbos/_queue.py
CHANGED
|
@@ -51,13 +51,13 @@ class Queue:
|
|
|
51
51
|
return start_workflow(dbos, func, self.name, False, *args, **kwargs)
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
def
|
|
54
|
+
def queue_thread(stop_event: threading.Event, dbos: "DBOS") -> None:
|
|
55
55
|
while not stop_event.is_set():
|
|
56
56
|
if stop_event.wait(timeout=1):
|
|
57
57
|
return
|
|
58
58
|
for _, queue in dbos._registry.queue_info_map.items():
|
|
59
59
|
try:
|
|
60
|
-
wf_ids = dbos._sys_db.start_queued_workflows(queue)
|
|
60
|
+
wf_ids = dbos._sys_db.start_queued_workflows(queue, dbos._executor_id)
|
|
61
61
|
for id in wf_ids:
|
|
62
62
|
execute_workflow_by_id(dbos, id)
|
|
63
63
|
except Exception:
|
dbos/_sys_db.py
CHANGED
|
@@ -1104,7 +1104,7 @@ class SystemDatabase:
|
|
|
1104
1104
|
.on_conflict_do_nothing()
|
|
1105
1105
|
)
|
|
1106
1106
|
|
|
1107
|
-
def start_queued_workflows(self, queue: "Queue") -> List[str]:
|
|
1107
|
+
def start_queued_workflows(self, queue: "Queue", executor_id: str) -> List[str]:
|
|
1108
1108
|
start_time_ms = int(time.time() * 1000)
|
|
1109
1109
|
if queue.limiter is not None:
|
|
1110
1110
|
limiter_period_ms = int(queue.limiter["period"] * 1000)
|
|
@@ -1159,7 +1159,7 @@ class SystemDatabase:
|
|
|
1159
1159
|
if len(ret_ids) + num_recent_queries >= queue.limiter["limit"]:
|
|
1160
1160
|
break
|
|
1161
1161
|
|
|
1162
|
-
# To start a function, first set its status to PENDING
|
|
1162
|
+
# To start a function, first set its status to PENDING and update its executor ID
|
|
1163
1163
|
c.execute(
|
|
1164
1164
|
SystemSchema.workflow_status.update()
|
|
1165
1165
|
.where(SystemSchema.workflow_status.c.workflow_uuid == id)
|
|
@@ -1167,7 +1167,10 @@ class SystemDatabase:
|
|
|
1167
1167
|
SystemSchema.workflow_status.c.status
|
|
1168
1168
|
== WorkflowStatusString.ENQUEUED.value
|
|
1169
1169
|
)
|
|
1170
|
-
.values(
|
|
1170
|
+
.values(
|
|
1171
|
+
status=WorkflowStatusString.PENDING.value,
|
|
1172
|
+
executor_id=executor_id,
|
|
1173
|
+
)
|
|
1171
1174
|
)
|
|
1172
1175
|
|
|
1173
1176
|
# Then give it a start time
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
dbos-0.
|
|
2
|
-
dbos-0.
|
|
3
|
-
dbos-0.
|
|
4
|
-
dbos-0.
|
|
1
|
+
dbos-0.17.0.dist-info/METADATA,sha256=jFKo8TAjYuyNqaNqT6YpSBvRzFVuTW8uws5cODC_25Q,5020
|
|
2
|
+
dbos-0.17.0.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
|
3
|
+
dbos-0.17.0.dist-info/entry_points.txt,sha256=z6GcVANQV7Uw_82H9Ob2axJX6V3imftyZsljdh-M1HU,54
|
|
4
|
+
dbos-0.17.0.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
|
|
5
5
|
dbos/__init__.py,sha256=CxRHBHEthPL4PZoLbZhp3rdm44-KkRTT2-7DkK9d4QQ,724
|
|
6
6
|
dbos/_admin_server.py,sha256=DOgzVp9kmwiebQqmJB1LcrZnGTxSMbZiGXdenc1wZDg,3163
|
|
7
7
|
dbos/_app_db.py,sha256=_tv2vmPjjiaikwgxH3mqxgJ4nUUcG2-0uMXKWCqVu1c,5509
|
|
8
8
|
dbos/_classproperty.py,sha256=f0X-_BySzn3yFDRKB2JpCbLYQ9tLwt1XftfshvY7CBs,626
|
|
9
9
|
dbos/_context.py,sha256=KV3fd3-Rv6EWrYDUdHARxltSlNZGNtQtNSqeQ-gkXE8,18049
|
|
10
|
-
dbos/_core.py,sha256=
|
|
10
|
+
dbos/_core.py,sha256=NWJFQX5bECBvKlYH9pVmNJgmqFGYPnkHnOGjOlOQ3Ag,33504
|
|
11
11
|
dbos/_croniter.py,sha256=hbhgfsHBqclUS8VeLnJ9PSE9Z54z6mi4nnrr1aUXn0k,47561
|
|
12
|
-
dbos/_dbos.py,sha256=
|
|
12
|
+
dbos/_dbos.py,sha256=riYx_dkYFzqeVDYpmcA5ABdAYQFhwyDi4AwxIihDNKA,34809
|
|
13
13
|
dbos/_dbos_config.py,sha256=f37eccN3JpCA32kRdQ4UsERjhYGcdLWv-N21ijnDZmY,6406
|
|
14
14
|
dbos/_error.py,sha256=UETk8CoZL-TO2Utn1-E7OSWelhShWmKM-fOlODMR9PE,3893
|
|
15
15
|
dbos/_fastapi.py,sha256=iyefCZq-ZDKRUjN_rgYQmFmyvWf4gPrSlC6CLbfq4a8,3419
|
|
@@ -25,8 +25,8 @@ dbos/_migrations/versions/a3b18ad34abe_added_triggers.py,sha256=Rv0ZsZYZ_WdgGEUL
|
|
|
25
25
|
dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py,sha256=8PyFi8rd6CN-mUro43wGhsg5wcQWKZPRHD6jw8R5pVc,986
|
|
26
26
|
dbos/_migrations/versions/d76646551a6c_workflow_queue.py,sha256=G942nophZ2uC2vc4hGBC02Ptng1715roTjY3xiyzZU4,729
|
|
27
27
|
dbos/_migrations/versions/eab0cc1d9a14_job_queue.py,sha256=uvhFOtqbBreCePhAxZfIT0qCAI7BiZTou9wt6QnbY7c,1412
|
|
28
|
-
dbos/_outcome.py,sha256=
|
|
29
|
-
dbos/_queue.py,sha256=
|
|
28
|
+
dbos/_outcome.py,sha256=FDMgWVjZ06vm9xO-38H17mTqBImUYQxgKs_bDCSIAhE,6648
|
|
29
|
+
dbos/_queue.py,sha256=5NZ6RfKQd8LQD8EeUXgrwu86r0AadKEqPIMmL_1ORuw,1956
|
|
30
30
|
dbos/_recovery.py,sha256=jbzGYxICA2drzyzlBSy2UiXhKV_16tBVacKQdTkqf-w,2008
|
|
31
31
|
dbos/_registrations.py,sha256=mei6q6_3R5uei8i_Wo_TqGZs85s10shOekDX41sFYD0,6642
|
|
32
32
|
dbos/_request.py,sha256=cX1B3Atlh160phgS35gF1VEEV4pD126c9F3BDgBmxZU,929
|
|
@@ -36,7 +36,7 @@ dbos/_schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
36
36
|
dbos/_schemas/application_database.py,sha256=KeyoPrF7hy_ODXV7QNike_VFSD74QBRfQ76D7QyE9HI,966
|
|
37
37
|
dbos/_schemas/system_database.py,sha256=7iw7eHJzEvkatHMOaHORoSvtfisF73wW5j8hRt_Ph14,5126
|
|
38
38
|
dbos/_serialization.py,sha256=YCYv0qKAwAZ1djZisBC7khvKqG-5OcIv9t9EC5PFIog,1743
|
|
39
|
-
dbos/_sys_db.py,sha256=
|
|
39
|
+
dbos/_sys_db.py,sha256=uZKeCnGc2MgvEd0ID3nReBBZj21HzClP56TFkXTvIZE,49028
|
|
40
40
|
dbos/_templates/hello/README.md,sha256=GhxhBj42wjTt1fWEtwNriHbJuKb66Vzu89G4pxNHw2g,930
|
|
41
41
|
dbos/_templates/hello/__package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
42
|
dbos/_templates/hello/__package/main.py,sha256=eI0SS9Nwj-fldtiuSzIlIG6dC91GXXwdRsoHxv6S_WI,2719
|
|
@@ -52,4 +52,4 @@ dbos/cli.py,sha256=em1uAxrp5yyg53V7ZpmHFtqD6OJp2cMJkG9vGJPoFTA,10904
|
|
|
52
52
|
dbos/dbos-config.schema.json,sha256=tS7x-bdFbFvpobcs3pIOhwun3yr_ndvTEYOn4BJjTzs,5889
|
|
53
53
|
dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
|
|
54
54
|
version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
|
|
55
|
-
dbos-0.
|
|
55
|
+
dbos-0.17.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|