dbos 0.21.0a5__py3-none-any.whl → 0.21.0a7__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/_dbos.py +4 -1
- dbos/_recovery.py +31 -11
- dbos/_sys_db.py +37 -6
- {dbos-0.21.0a5.dist-info → dbos-0.21.0a7.dist-info}/METADATA +1 -1
- {dbos-0.21.0a5.dist-info → dbos-0.21.0a7.dist-info}/RECORD +8 -8
- {dbos-0.21.0a5.dist-info → dbos-0.21.0a7.dist-info}/WHEEL +0 -0
- {dbos-0.21.0a5.dist-info → dbos-0.21.0a7.dist-info}/entry_points.txt +0 -0
- {dbos-0.21.0a5.dist-info → dbos-0.21.0a7.dist-info}/licenses/LICENSE +0 -0
dbos/_dbos.py
CHANGED
|
@@ -56,7 +56,7 @@ from ._registrations import (
|
|
|
56
56
|
)
|
|
57
57
|
from ._roles import default_required_roles, required_roles
|
|
58
58
|
from ._scheduler import ScheduledWorkflow, scheduled
|
|
59
|
-
from ._sys_db import
|
|
59
|
+
from ._sys_db import reset_system_database
|
|
60
60
|
from ._tracer import dbos_tracer
|
|
61
61
|
|
|
62
62
|
if TYPE_CHECKING:
|
|
@@ -613,6 +613,7 @@ class DBOS:
|
|
|
613
613
|
workflow_id=workflow_id,
|
|
614
614
|
status=stat["status"],
|
|
615
615
|
name=stat["name"],
|
|
616
|
+
executor_id=stat["executor_id"],
|
|
616
617
|
recovery_attempts=stat["recovery_attempts"],
|
|
617
618
|
class_name=stat["class_name"],
|
|
618
619
|
config_name=stat["config_name"],
|
|
@@ -909,6 +910,7 @@ class WorkflowStatus:
|
|
|
909
910
|
workflow_id(str): The ID of the workflow execution
|
|
910
911
|
status(str): The status of the execution, from `WorkflowStatusString`
|
|
911
912
|
name(str): The workflow function name
|
|
913
|
+
executor_id(str): The ID of the executor running the workflow
|
|
912
914
|
class_name(str): For member functions, the name of the class containing the workflow function
|
|
913
915
|
config_name(str): For instance member functions, the name of the class instance for the execution
|
|
914
916
|
queue_name(str): For workflows that are or were queued, the queue name
|
|
@@ -922,6 +924,7 @@ class WorkflowStatus:
|
|
|
922
924
|
workflow_id: str
|
|
923
925
|
status: str
|
|
924
926
|
name: str
|
|
927
|
+
executor_id: Optional[str]
|
|
925
928
|
class_name: Optional[str]
|
|
926
929
|
config_name: Optional[str]
|
|
927
930
|
queue_name: Optional[str]
|
dbos/_recovery.py
CHANGED
|
@@ -6,20 +6,29 @@ from typing import TYPE_CHECKING, Any, List
|
|
|
6
6
|
|
|
7
7
|
from ._core import execute_workflow_by_id
|
|
8
8
|
from ._error import DBOSWorkflowFunctionNotFoundError
|
|
9
|
+
from ._sys_db import GetPendingWorkflowsOutput
|
|
9
10
|
|
|
10
11
|
if TYPE_CHECKING:
|
|
11
12
|
from ._dbos import DBOS, WorkflowHandle
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
def startup_recovery_thread(
|
|
15
|
+
def startup_recovery_thread(
|
|
16
|
+
dbos: "DBOS", pending_workflows: List[GetPendingWorkflowsOutput]
|
|
17
|
+
) -> None:
|
|
15
18
|
"""Attempt to recover local pending workflows on startup using a background thread."""
|
|
16
19
|
stop_event = threading.Event()
|
|
17
20
|
dbos.stop_events.append(stop_event)
|
|
18
|
-
while not stop_event.is_set() and len(
|
|
21
|
+
while not stop_event.is_set() and len(pending_workflows) > 0:
|
|
19
22
|
try:
|
|
20
|
-
for
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
for pending_workflow in list(pending_workflows):
|
|
24
|
+
if (
|
|
25
|
+
pending_workflow.queue_name
|
|
26
|
+
and pending_workflow.queue_name != "_dbos_internal_queue"
|
|
27
|
+
):
|
|
28
|
+
dbos._sys_db.clear_queue_assignment(pending_workflow.workflow_uuid)
|
|
29
|
+
continue
|
|
30
|
+
execute_workflow_by_id(dbos, pending_workflow.workflow_uuid)
|
|
31
|
+
pending_workflows.remove(pending_workflow)
|
|
23
32
|
except DBOSWorkflowFunctionNotFoundError:
|
|
24
33
|
time.sleep(1)
|
|
25
34
|
except Exception as e:
|
|
@@ -39,12 +48,23 @@ def recover_pending_workflows(
|
|
|
39
48
|
f"Skip local recovery because it's running in a VM: {os.environ.get('DBOS__VMID')}"
|
|
40
49
|
)
|
|
41
50
|
dbos.logger.debug(f"Recovering pending workflows for executor: {executor_id}")
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
pending_workflows = dbos._sys_db.get_pending_workflows(executor_id)
|
|
52
|
+
for pending_workflow in pending_workflows:
|
|
53
|
+
if (
|
|
54
|
+
pending_workflow.queue_name
|
|
55
|
+
and pending_workflow.queue_name != "_dbos_internal_queue"
|
|
56
|
+
):
|
|
57
|
+
try:
|
|
58
|
+
dbos._sys_db.clear_queue_assignment(pending_workflow.workflow_uuid)
|
|
59
|
+
workflow_handles.append(
|
|
60
|
+
dbos.retrieve_workflow(pending_workflow.workflow_uuid)
|
|
61
|
+
)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
dbos.logger.error(e)
|
|
64
|
+
else:
|
|
65
|
+
workflow_handles.append(
|
|
66
|
+
execute_workflow_by_id(dbos, pending_workflow.workflow_uuid)
|
|
67
|
+
)
|
|
48
68
|
|
|
49
69
|
dbos.logger.info("Recovered pending workflows")
|
|
50
70
|
return workflow_handles
|
dbos/_sys_db.py
CHANGED
|
@@ -140,6 +140,12 @@ class GetWorkflowsOutput:
|
|
|
140
140
|
self.workflow_uuids = workflow_uuids
|
|
141
141
|
|
|
142
142
|
|
|
143
|
+
class GetPendingWorkflowsOutput:
|
|
144
|
+
def __init__(self, *, workflow_uuid: str, queue_name: Optional[str] = None):
|
|
145
|
+
self.workflow_uuid: str = workflow_uuid
|
|
146
|
+
self.queue_name: Optional[str] = queue_name
|
|
147
|
+
|
|
148
|
+
|
|
143
149
|
class WorkflowInformation(TypedDict, total=False):
|
|
144
150
|
workflow_uuid: str
|
|
145
151
|
status: WorkflowStatuses # The status of the workflow.
|
|
@@ -465,6 +471,7 @@ class SystemDatabase:
|
|
|
465
471
|
SystemSchema.workflow_status.c.authenticated_roles,
|
|
466
472
|
SystemSchema.workflow_status.c.assumed_role,
|
|
467
473
|
SystemSchema.workflow_status.c.queue_name,
|
|
474
|
+
SystemSchema.workflow_status.c.executor_id,
|
|
468
475
|
).where(SystemSchema.workflow_status.c.workflow_uuid == workflow_uuid)
|
|
469
476
|
).fetchone()
|
|
470
477
|
if row is None:
|
|
@@ -479,7 +486,7 @@ class SystemDatabase:
|
|
|
479
486
|
"error": None,
|
|
480
487
|
"app_id": None,
|
|
481
488
|
"app_version": None,
|
|
482
|
-
"executor_id":
|
|
489
|
+
"executor_id": row[10],
|
|
483
490
|
"request": row[2],
|
|
484
491
|
"recovery_attempts": row[3],
|
|
485
492
|
"authenticated_user": row[6],
|
|
@@ -665,7 +672,7 @@ class SystemDatabase:
|
|
|
665
672
|
|
|
666
673
|
def get_workflows(self, input: GetWorkflowsInput) -> GetWorkflowsOutput:
|
|
667
674
|
query = sa.select(SystemSchema.workflow_status.c.workflow_uuid).order_by(
|
|
668
|
-
SystemSchema.workflow_status.c.created_at.
|
|
675
|
+
SystemSchema.workflow_status.c.created_at.asc()
|
|
669
676
|
)
|
|
670
677
|
if input.name:
|
|
671
678
|
query = query.where(SystemSchema.workflow_status.c.name == input.name)
|
|
@@ -711,7 +718,7 @@ class SystemDatabase:
|
|
|
711
718
|
SystemSchema.workflow_queue.c.workflow_uuid
|
|
712
719
|
== SystemSchema.workflow_status.c.workflow_uuid,
|
|
713
720
|
)
|
|
714
|
-
.order_by(SystemSchema.workflow_status.c.created_at.
|
|
721
|
+
.order_by(SystemSchema.workflow_status.c.created_at.asc())
|
|
715
722
|
)
|
|
716
723
|
|
|
717
724
|
if input.get("name"):
|
|
@@ -746,16 +753,27 @@ class SystemDatabase:
|
|
|
746
753
|
|
|
747
754
|
return GetWorkflowsOutput(workflow_uuids)
|
|
748
755
|
|
|
749
|
-
def get_pending_workflows(
|
|
756
|
+
def get_pending_workflows(
|
|
757
|
+
self, executor_id: str
|
|
758
|
+
) -> list[GetPendingWorkflowsOutput]:
|
|
750
759
|
with self.engine.begin() as c:
|
|
751
760
|
rows = c.execute(
|
|
752
|
-
sa.select(
|
|
761
|
+
sa.select(
|
|
762
|
+
SystemSchema.workflow_status.c.workflow_uuid,
|
|
763
|
+
SystemSchema.workflow_status.c.queue_name,
|
|
764
|
+
).where(
|
|
753
765
|
SystemSchema.workflow_status.c.status
|
|
754
766
|
== WorkflowStatusString.PENDING.value,
|
|
755
767
|
SystemSchema.workflow_status.c.executor_id == executor_id,
|
|
756
768
|
)
|
|
757
769
|
).fetchall()
|
|
758
|
-
return [
|
|
770
|
+
return [
|
|
771
|
+
GetPendingWorkflowsOutput(
|
|
772
|
+
workflow_uuid=row.workflow_uuid,
|
|
773
|
+
queue_name=row.queue_name,
|
|
774
|
+
)
|
|
775
|
+
for row in rows
|
|
776
|
+
]
|
|
759
777
|
|
|
760
778
|
def record_operation_result(
|
|
761
779
|
self, result: OperationResultInternal, conn: Optional[sa.Connection] = None
|
|
@@ -1375,6 +1393,19 @@ class SystemDatabase:
|
|
|
1375
1393
|
.values(completed_at_epoch_ms=int(time.time() * 1000))
|
|
1376
1394
|
)
|
|
1377
1395
|
|
|
1396
|
+
def clear_queue_assignment(self, workflow_id: str) -> None:
|
|
1397
|
+
with self.engine.begin() as c:
|
|
1398
|
+
c.execute(
|
|
1399
|
+
sa.update(SystemSchema.workflow_queue)
|
|
1400
|
+
.where(SystemSchema.workflow_queue.c.workflow_uuid == workflow_id)
|
|
1401
|
+
.values(executor_id=None, started_at_epoch_ms=None)
|
|
1402
|
+
)
|
|
1403
|
+
c.execute(
|
|
1404
|
+
sa.update(SystemSchema.workflow_status)
|
|
1405
|
+
.where(SystemSchema.workflow_status.c.workflow_uuid == workflow_id)
|
|
1406
|
+
.values(executor_id=None, status=WorkflowStatusString.ENQUEUED.value)
|
|
1407
|
+
)
|
|
1408
|
+
|
|
1378
1409
|
|
|
1379
1410
|
def reset_system_database(config: ConfigFile) -> None:
|
|
1380
1411
|
sysdb_name = (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
dbos-0.21.
|
|
2
|
-
dbos-0.21.
|
|
3
|
-
dbos-0.21.
|
|
4
|
-
dbos-0.21.
|
|
1
|
+
dbos-0.21.0a7.dist-info/METADATA,sha256=76OQDkyQg_N8Yg1zzmRXJ34Kofg1rX7VgTkhX7mMlnI,5309
|
|
2
|
+
dbos-0.21.0a7.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
|
3
|
+
dbos-0.21.0a7.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
|
|
4
|
+
dbos-0.21.0a7.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=PJgneZG9-64TapZrPeJtt73puAswRImCE5uce2k2PKU,4750
|
|
7
7
|
dbos/_app_db.py,sha256=_tv2vmPjjiaikwgxH3mqxgJ4nUUcG2-0uMXKWCqVu1c,5509
|
|
@@ -13,7 +13,7 @@ dbos/_context.py,sha256=FHB_fpE4fQt4fIJvAmMMsbY4xHwH77gsW01cFsRZjsE,17779
|
|
|
13
13
|
dbos/_core.py,sha256=nGiXyYgV8H5TRRZG0e8HCd5IZimufYQLmKNr7nBbwbo,36564
|
|
14
14
|
dbos/_croniter.py,sha256=hbhgfsHBqclUS8VeLnJ9PSE9Z54z6mi4nnrr1aUXn0k,47561
|
|
15
15
|
dbos/_db_wizard.py,sha256=xgKLna0_6Xi50F3o8msRosXba8NScHlpJR5ICVCkHDQ,7534
|
|
16
|
-
dbos/_dbos.py,sha256=
|
|
16
|
+
dbos/_dbos.py,sha256=wAjdlUgDSIC_Q8D_GZYDoiKaxjtr6KNHeq6DDuUh9do,36340
|
|
17
17
|
dbos/_dbos_config.py,sha256=DfiqVVxNqnafkocSzLqBp1Ig5vCviDTDK_GO3zTtQqI,8298
|
|
18
18
|
dbos/_error.py,sha256=vtaSsG0QW6cRlwfZ4zzZWy_IHCZlomwSlrDyGWuyn8c,4337
|
|
19
19
|
dbos/_fastapi.py,sha256=ke03vqsSYDnO6XeOtOVFXj0-f-v1MGsOxa9McaROvNc,3616
|
|
@@ -32,7 +32,7 @@ dbos/_migrations/versions/d76646551a6c_workflow_queue.py,sha256=G942nophZ2uC2vc4
|
|
|
32
32
|
dbos/_migrations/versions/eab0cc1d9a14_job_queue.py,sha256=uvhFOtqbBreCePhAxZfIT0qCAI7BiZTou9wt6QnbY7c,1412
|
|
33
33
|
dbos/_outcome.py,sha256=FDMgWVjZ06vm9xO-38H17mTqBImUYQxgKs_bDCSIAhE,6648
|
|
34
34
|
dbos/_queue.py,sha256=o_aczwualJTMoXb0XXL-Y5QH77OEukWzuerogbWi2ho,2779
|
|
35
|
-
dbos/_recovery.py,sha256=
|
|
35
|
+
dbos/_recovery.py,sha256=rek9rm2CaENbbl_vu3To-BdXop7tMEyGvtoNiJLVxjQ,2772
|
|
36
36
|
dbos/_registrations.py,sha256=mei6q6_3R5uei8i_Wo_TqGZs85s10shOekDX41sFYD0,6642
|
|
37
37
|
dbos/_request.py,sha256=cX1B3Atlh160phgS35gF1VEEV4pD126c9F3BDgBmxZU,929
|
|
38
38
|
dbos/_roles.py,sha256=iOsgmIAf1XVzxs3gYWdGRe1B880YfOw5fpU7Jwx8_A8,2271
|
|
@@ -41,7 +41,7 @@ dbos/_schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
41
41
|
dbos/_schemas/application_database.py,sha256=KeyoPrF7hy_ODXV7QNike_VFSD74QBRfQ76D7QyE9HI,966
|
|
42
42
|
dbos/_schemas/system_database.py,sha256=rwp4EvCSaXcUoMaRczZCvETCxGp72k3-hvLyGUDkih0,5163
|
|
43
43
|
dbos/_serialization.py,sha256=YCYv0qKAwAZ1djZisBC7khvKqG-5OcIv9t9EC5PFIog,1743
|
|
44
|
-
dbos/_sys_db.py,sha256=
|
|
44
|
+
dbos/_sys_db.py,sha256=U5rXoS2gA4vm8YT6Rja_YyP2EXWLlo1HqDka1tnpRjk,59460
|
|
45
45
|
dbos/_templates/dbos-db-starter/README.md,sha256=GhxhBj42wjTt1fWEtwNriHbJuKb66Vzu89G4pxNHw2g,930
|
|
46
46
|
dbos/_templates/dbos-db-starter/__package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
47
|
dbos/_templates/dbos-db-starter/__package/main.py,sha256=eI0SS9Nwj-fldtiuSzIlIG6dC91GXXwdRsoHxv6S_WI,2719
|
|
@@ -60,4 +60,4 @@ dbos/cli/cli.py,sha256=_tXw2IQrWW7fV_h51f_R99vEBSi6aMLz-vCOxKaENiQ,14155
|
|
|
60
60
|
dbos/dbos-config.schema.json,sha256=X5TpXNcARGceX0zQs0fVgtZW_Xj9uBbY5afPt9Rz9yk,5741
|
|
61
61
|
dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
|
|
62
62
|
version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
|
|
63
|
-
dbos-0.21.
|
|
63
|
+
dbos-0.21.0a7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|