dbos 0.26.0a18__py3-none-any.whl → 0.26.0a21__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/__init__.py +1 -2
- dbos/_app_db.py +4 -1
- dbos/_client.py +40 -6
- dbos/_conductor/protocol.py +1 -2
- dbos/_core.py +10 -9
- dbos/_dbos.py +23 -32
- dbos/_registrations.py +1 -1
- dbos/_sys_db.py +183 -21
- dbos/_workflow_commands.py +35 -102
- {dbos-0.26.0a18.dist-info → dbos-0.26.0a21.dist-info}/METADATA +1 -1
- {dbos-0.26.0a18.dist-info → dbos-0.26.0a21.dist-info}/RECORD +14 -14
- {dbos-0.26.0a18.dist-info → dbos-0.26.0a21.dist-info}/WHEEL +0 -0
- {dbos-0.26.0a18.dist-info → dbos-0.26.0a21.dist-info}/entry_points.txt +0 -0
- {dbos-0.26.0a18.dist-info → dbos-0.26.0a21.dist-info}/licenses/LICENSE +0 -0
dbos/__init__.py
CHANGED
@@ -5,8 +5,7 @@ from ._dbos import DBOS, DBOSConfiguredInstance, WorkflowHandle
|
|
5
5
|
from ._dbos_config import ConfigFile, DBOSConfig, get_dbos_database_url, load_config
|
6
6
|
from ._kafka_message import KafkaMessage
|
7
7
|
from ._queue import Queue
|
8
|
-
from ._sys_db import GetWorkflowsInput, WorkflowStatusString
|
9
|
-
from ._workflow_commands import WorkflowStatus
|
8
|
+
from ._sys_db import GetWorkflowsInput, WorkflowStatus, WorkflowStatusString
|
10
9
|
|
11
10
|
__all__ = [
|
12
11
|
"ConfigFile",
|
dbos/_app_db.py
CHANGED
@@ -74,9 +74,12 @@ class ApplicationDatabase:
|
|
74
74
|
database["connectionTimeoutMillis"] / 1000
|
75
75
|
)
|
76
76
|
|
77
|
+
pool_size = database.get("app_db_pool_size")
|
78
|
+
if pool_size is None:
|
79
|
+
pool_size = 20
|
77
80
|
self.engine = sa.create_engine(
|
78
81
|
app_db_url,
|
79
|
-
pool_size=
|
82
|
+
pool_size=pool_size,
|
80
83
|
max_overflow=0,
|
81
84
|
pool_timeout=30,
|
82
85
|
connect_args=connect_args,
|
dbos/_client.py
CHANGED
@@ -3,6 +3,8 @@ import sys
|
|
3
3
|
import uuid
|
4
4
|
from typing import Any, Generic, List, Optional, TypedDict, TypeVar
|
5
5
|
|
6
|
+
from dbos._app_db import ApplicationDatabase
|
7
|
+
|
6
8
|
if sys.version_info < (3, 11):
|
7
9
|
from typing_extensions import NotRequired
|
8
10
|
else:
|
@@ -14,11 +16,18 @@ from dbos._dbos_config import parse_database_url_to_dbconfig
|
|
14
16
|
from dbos._error import DBOSNonExistentWorkflowError
|
15
17
|
from dbos._registrations import DEFAULT_MAX_RECOVERY_ATTEMPTS
|
16
18
|
from dbos._serialization import WorkflowInputs
|
17
|
-
from dbos._sys_db import
|
18
|
-
|
19
|
+
from dbos._sys_db import (
|
20
|
+
StepInfo,
|
21
|
+
SystemDatabase,
|
19
22
|
WorkflowStatus,
|
23
|
+
WorkflowStatusInternal,
|
24
|
+
WorkflowStatusString,
|
25
|
+
)
|
26
|
+
from dbos._workflow_commands import (
|
27
|
+
fork_workflow,
|
20
28
|
get_workflow,
|
21
29
|
list_queued_workflows,
|
30
|
+
list_workflow_steps,
|
22
31
|
list_workflows,
|
23
32
|
)
|
24
33
|
|
@@ -45,7 +54,7 @@ class WorkflowHandleClientPolling(Generic[R]):
|
|
45
54
|
res: R = self._sys_db.await_workflow_result(self.workflow_id)
|
46
55
|
return res
|
47
56
|
|
48
|
-
def get_status(self) ->
|
57
|
+
def get_status(self) -> WorkflowStatus:
|
49
58
|
status = get_workflow(self._sys_db, self.workflow_id, True)
|
50
59
|
if status is None:
|
51
60
|
raise DBOSNonExistentWorkflowError(self.workflow_id)
|
@@ -67,7 +76,7 @@ class WorkflowHandleClientAsyncPolling(Generic[R]):
|
|
67
76
|
)
|
68
77
|
return res
|
69
78
|
|
70
|
-
async def get_status(self) ->
|
79
|
+
async def get_status(self) -> WorkflowStatus:
|
71
80
|
status = await asyncio.to_thread(
|
72
81
|
get_workflow, self._sys_db, self.workflow_id, True
|
73
82
|
)
|
@@ -82,6 +91,7 @@ class DBOSClient:
|
|
82
91
|
if system_database is not None:
|
83
92
|
db_config["sys_db_name"] = system_database
|
84
93
|
self._sys_db = SystemDatabase(db_config)
|
94
|
+
self._app_db = ApplicationDatabase(db_config)
|
85
95
|
|
86
96
|
def destroy(self) -> None:
|
87
97
|
self._sys_db.destroy()
|
@@ -124,7 +134,9 @@ class DBOSClient:
|
|
124
134
|
"kwargs": kwargs,
|
125
135
|
}
|
126
136
|
|
127
|
-
self._sys_db.init_workflow(
|
137
|
+
self._sys_db.init_workflow(
|
138
|
+
status, _serialization.serialize_args(inputs), max_recovery_attempts=None
|
139
|
+
)
|
128
140
|
return workflow_id
|
129
141
|
|
130
142
|
def enqueue(
|
@@ -180,7 +192,9 @@ class DBOSClient:
|
|
180
192
|
"app_version": None,
|
181
193
|
}
|
182
194
|
with self._sys_db.engine.begin() as conn:
|
183
|
-
self._sys_db.insert_workflow_status(
|
195
|
+
self._sys_db.insert_workflow_status(
|
196
|
+
status, conn, max_recovery_attempts=None
|
197
|
+
)
|
184
198
|
self._sys_db.send(status["workflow_uuid"], 0, destination_id, message, topic)
|
185
199
|
|
186
200
|
async def send_async(
|
@@ -321,3 +335,23 @@ class DBOSClient:
|
|
321
335
|
offset=offset,
|
322
336
|
sort_desc=sort_desc,
|
323
337
|
)
|
338
|
+
|
339
|
+
def list_workflow_steps(self, workflow_id: str) -> List[StepInfo]:
|
340
|
+
return list_workflow_steps(self._sys_db, self._app_db, workflow_id)
|
341
|
+
|
342
|
+
async def list_workflow_steps_async(self, workflow_id: str) -> List[StepInfo]:
|
343
|
+
return await asyncio.to_thread(self.list_workflow_steps, workflow_id)
|
344
|
+
|
345
|
+
def fork_workflow(self, workflow_id: str, start_step: int) -> WorkflowHandle[R]:
|
346
|
+
forked_workflow_id = fork_workflow(
|
347
|
+
self._sys_db, self._app_db, workflow_id, start_step
|
348
|
+
)
|
349
|
+
return WorkflowHandleClientPolling[R](forked_workflow_id, self._sys_db)
|
350
|
+
|
351
|
+
async def fork_workflow_async(
|
352
|
+
self, workflow_id: str, start_step: int
|
353
|
+
) -> WorkflowHandleAsync[R]:
|
354
|
+
forked_workflow_id = await asyncio.to_thread(
|
355
|
+
fork_workflow, self._sys_db, self._app_db, workflow_id, start_step
|
356
|
+
)
|
357
|
+
return WorkflowHandleClientAsyncPolling[R](forked_workflow_id, self._sys_db)
|
dbos/_conductor/protocol.py
CHANGED
@@ -3,8 +3,7 @@ from dataclasses import asdict, dataclass
|
|
3
3
|
from enum import Enum
|
4
4
|
from typing import List, Optional, Type, TypedDict, TypeVar
|
5
5
|
|
6
|
-
from dbos._sys_db import StepInfo
|
7
|
-
from dbos._workflow_commands import WorkflowStatus
|
6
|
+
from dbos._sys_db import StepInfo, WorkflowStatus
|
8
7
|
|
9
8
|
|
10
9
|
class MessageType(str, Enum):
|
dbos/_core.py
CHANGED
@@ -75,6 +75,7 @@ from ._serialization import WorkflowInputs
|
|
75
75
|
from ._sys_db import (
|
76
76
|
GetEventWorkflowContext,
|
77
77
|
OperationResultInternal,
|
78
|
+
WorkflowStatus,
|
78
79
|
WorkflowStatusInternal,
|
79
80
|
WorkflowStatusString,
|
80
81
|
)
|
@@ -87,7 +88,6 @@ if TYPE_CHECKING:
|
|
87
88
|
DBOSRegistry,
|
88
89
|
IsolationLevel,
|
89
90
|
)
|
90
|
-
from ._workflow_commands import WorkflowStatus
|
91
91
|
|
92
92
|
from sqlalchemy.exc import DBAPIError, InvalidRequestError
|
93
93
|
|
@@ -119,7 +119,7 @@ class WorkflowHandleFuture(Generic[R]):
|
|
119
119
|
self.dbos._sys_db.record_get_result(self.workflow_id, serialized_r, None)
|
120
120
|
return r
|
121
121
|
|
122
|
-
def get_status(self) ->
|
122
|
+
def get_status(self) -> WorkflowStatus:
|
123
123
|
stat = self.dbos.get_workflow_status(self.workflow_id)
|
124
124
|
if stat is None:
|
125
125
|
raise DBOSNonExistentWorkflowError(self.workflow_id)
|
@@ -146,7 +146,7 @@ class WorkflowHandlePolling(Generic[R]):
|
|
146
146
|
self.dbos._sys_db.record_get_result(self.workflow_id, serialized_r, None)
|
147
147
|
return r
|
148
148
|
|
149
|
-
def get_status(self) ->
|
149
|
+
def get_status(self) -> WorkflowStatus:
|
150
150
|
stat = self.dbos.get_workflow_status(self.workflow_id)
|
151
151
|
if stat is None:
|
152
152
|
raise DBOSNonExistentWorkflowError(self.workflow_id)
|
@@ -181,7 +181,7 @@ class WorkflowHandleAsyncTask(Generic[R]):
|
|
181
181
|
)
|
182
182
|
return r
|
183
183
|
|
184
|
-
async def get_status(self) ->
|
184
|
+
async def get_status(self) -> WorkflowStatus:
|
185
185
|
stat = await asyncio.to_thread(self.dbos.get_workflow_status, self.workflow_id)
|
186
186
|
if stat is None:
|
187
187
|
raise DBOSNonExistentWorkflowError(self.workflow_id)
|
@@ -217,7 +217,7 @@ class WorkflowHandleAsyncPolling(Generic[R]):
|
|
217
217
|
)
|
218
218
|
return r
|
219
219
|
|
220
|
-
async def get_status(self) ->
|
220
|
+
async def get_status(self) -> WorkflowStatus:
|
221
221
|
stat = await asyncio.to_thread(self.dbos.get_workflow_status, self.workflow_id)
|
222
222
|
if stat is None:
|
223
223
|
raise DBOSNonExistentWorkflowError(self.workflow_id)
|
@@ -232,8 +232,8 @@ def _init_workflow(
|
|
232
232
|
class_name: Optional[str],
|
233
233
|
config_name: Optional[str],
|
234
234
|
temp_wf_type: Optional[str],
|
235
|
-
queue: Optional[str]
|
236
|
-
max_recovery_attempts: int
|
235
|
+
queue: Optional[str],
|
236
|
+
max_recovery_attempts: Optional[int],
|
237
237
|
) -> WorkflowStatusInternal:
|
238
238
|
wfid = (
|
239
239
|
ctx.workflow_id
|
@@ -653,7 +653,7 @@ else:
|
|
653
653
|
def workflow_wrapper(
|
654
654
|
dbosreg: "DBOSRegistry",
|
655
655
|
func: Callable[P, R],
|
656
|
-
max_recovery_attempts: int = DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
656
|
+
max_recovery_attempts: Optional[int] = DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
657
657
|
) -> Callable[P, R]:
|
658
658
|
func.__orig_func = func # type: ignore
|
659
659
|
|
@@ -718,6 +718,7 @@ def workflow_wrapper(
|
|
718
718
|
class_name=get_dbos_class_name(fi, func, args),
|
719
719
|
config_name=get_config_name(fi, func, args),
|
720
720
|
temp_wf_type=get_temp_workflow_type(func),
|
721
|
+
queue=None,
|
721
722
|
max_recovery_attempts=max_recovery_attempts,
|
722
723
|
)
|
723
724
|
|
@@ -765,7 +766,7 @@ def workflow_wrapper(
|
|
765
766
|
|
766
767
|
|
767
768
|
def decorate_workflow(
|
768
|
-
reg: "DBOSRegistry", max_recovery_attempts: int
|
769
|
+
reg: "DBOSRegistry", max_recovery_attempts: Optional[int]
|
769
770
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
770
771
|
def _workflow_decorator(func: Callable[P, R]) -> Callable[P, R]:
|
771
772
|
wrapped_func = workflow_wrapper(reg, func, max_recovery_attempts)
|
dbos/_dbos.py
CHANGED
@@ -31,9 +31,10 @@ from typing import (
|
|
31
31
|
from opentelemetry.trace import Span
|
32
32
|
|
33
33
|
from dbos._conductor.conductor import ConductorWebsocket
|
34
|
+
from dbos._sys_db import WorkflowStatus
|
34
35
|
from dbos._utils import INTERNAL_QUEUE_NAME, GlobalParams
|
35
36
|
from dbos._workflow_commands import (
|
36
|
-
|
37
|
+
fork_workflow,
|
37
38
|
list_queued_workflows,
|
38
39
|
list_workflows,
|
39
40
|
)
|
@@ -67,7 +68,7 @@ from ._registrations import (
|
|
67
68
|
)
|
68
69
|
from ._roles import default_required_roles, required_roles
|
69
70
|
from ._scheduler import ScheduledWorkflow, scheduled
|
70
|
-
from ._sys_db import reset_system_database
|
71
|
+
from ._sys_db import StepInfo, WorkflowStatus, reset_system_database
|
71
72
|
from ._tracer import dbos_tracer
|
72
73
|
|
73
74
|
if TYPE_CHECKING:
|
@@ -113,7 +114,7 @@ from ._error import (
|
|
113
114
|
from ._event_loop import BackgroundEventLoop
|
114
115
|
from ._logger import add_otlp_to_all_loggers, config_logger, dbos_logger, init_logger
|
115
116
|
from ._sys_db import SystemDatabase
|
116
|
-
from ._workflow_commands import
|
117
|
+
from ._workflow_commands import get_workflow, list_workflow_steps
|
117
118
|
|
118
119
|
# Most DBOS functions are just any callable F, so decorators / wrappers work on F
|
119
120
|
# There are cases where the parameters P and return value R should be separate
|
@@ -599,7 +600,7 @@ class DBOS:
|
|
599
600
|
# Decorators for DBOS functionality
|
600
601
|
@classmethod
|
601
602
|
def workflow(
|
602
|
-
cls, *, max_recovery_attempts: int = DEFAULT_MAX_RECOVERY_ATTEMPTS
|
603
|
+
cls, *, max_recovery_attempts: Optional[int] = DEFAULT_MAX_RECOVERY_ATTEMPTS
|
603
604
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
604
605
|
"""Decorate a function for use as a DBOS workflow."""
|
605
606
|
return decorate_workflow(_get_or_create_dbos_registry(), max_recovery_attempts)
|
@@ -959,40 +960,19 @@ class DBOS:
|
|
959
960
|
@classmethod
|
960
961
|
def restart_workflow(cls, workflow_id: str) -> WorkflowHandle[Any]:
|
961
962
|
"""Restart a workflow with a new workflow ID"""
|
962
|
-
|
963
963
|
return cls.fork_workflow(workflow_id, 1)
|
964
964
|
|
965
965
|
@classmethod
|
966
|
-
def fork_workflow(
|
967
|
-
|
968
|
-
) -> WorkflowHandle[Any]:
|
969
|
-
"""Restart a workflow with a new workflow ID"""
|
970
|
-
|
971
|
-
def get_max_function_id(workflow_uuid: str) -> int:
|
972
|
-
max_transactions = (
|
973
|
-
_get_dbos_instance()._app_db.get_max_function_id(workflow_uuid) or 0
|
974
|
-
)
|
975
|
-
max_operations = (
|
976
|
-
_get_dbos_instance()._sys_db.get_max_function_id(workflow_uuid) or 0
|
977
|
-
)
|
978
|
-
return max(max_transactions, max_operations)
|
979
|
-
|
980
|
-
max_function_id = get_max_function_id(workflow_id)
|
981
|
-
if max_function_id > 0 and start_step > max_function_id:
|
982
|
-
raise DBOSException(
|
983
|
-
f"Cannot fork workflow {workflow_id} at step {start_step}. The workflow has {max_function_id} steps."
|
984
|
-
)
|
966
|
+
def fork_workflow(cls, workflow_id: str, start_step: int) -> WorkflowHandle[Any]:
|
967
|
+
"""Restart a workflow with a new workflow ID from a specific step"""
|
985
968
|
|
986
969
|
def fn() -> str:
|
987
|
-
forked_workflow_id = str(uuid.uuid4())
|
988
970
|
dbos_logger.info(f"Forking workflow: {workflow_id} from step {start_step}")
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
return _get_dbos_instance()._sys_db.fork_workflow(
|
995
|
-
workflow_id, forked_workflow_id, start_step
|
971
|
+
return fork_workflow(
|
972
|
+
_get_dbos_instance()._sys_db,
|
973
|
+
_get_dbos_instance()._app_db,
|
974
|
+
workflow_id,
|
975
|
+
start_step,
|
996
976
|
)
|
997
977
|
|
998
978
|
new_id = _get_dbos_instance()._sys_db.call_function_as_step(
|
@@ -1066,6 +1046,17 @@ class DBOS:
|
|
1066
1046
|
fn, "DBOS.listQueuedWorkflows"
|
1067
1047
|
)
|
1068
1048
|
|
1049
|
+
@classmethod
|
1050
|
+
def list_workflow_steps(cls, workflow_id: str) -> List[StepInfo]:
|
1051
|
+
def fn() -> List[StepInfo]:
|
1052
|
+
return list_workflow_steps(
|
1053
|
+
_get_dbos_instance()._sys_db, _get_dbos_instance()._app_db, workflow_id
|
1054
|
+
)
|
1055
|
+
|
1056
|
+
return _get_dbos_instance()._sys_db.call_function_as_step(
|
1057
|
+
fn, "DBOS.listWorkflowSteps"
|
1058
|
+
)
|
1059
|
+
|
1069
1060
|
@classproperty
|
1070
1061
|
def logger(cls) -> Logger:
|
1071
1062
|
"""Return the DBOS `Logger` for the current context."""
|
dbos/_registrations.py
CHANGED
@@ -51,7 +51,7 @@ class DBOSFuncInfo:
|
|
51
51
|
class_info: Optional[DBOSClassInfo] = None
|
52
52
|
func_type: DBOSFuncType = DBOSFuncType.Unknown
|
53
53
|
required_roles: Optional[List[str]] = None
|
54
|
-
max_recovery_attempts: int = DEFAULT_MAX_RECOVERY_ATTEMPTS
|
54
|
+
max_recovery_attempts: Optional[int] = DEFAULT_MAX_RECOVERY_ATTEMPTS
|
55
55
|
|
56
56
|
|
57
57
|
def get_or_create_class_info(
|
dbos/_sys_db.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import datetime
|
2
|
+
import json
|
2
3
|
import logging
|
3
4
|
import os
|
4
5
|
import re
|
@@ -64,6 +65,50 @@ WorkflowStatuses = Literal[
|
|
64
65
|
]
|
65
66
|
|
66
67
|
|
68
|
+
class WorkflowStatus:
|
69
|
+
# The workflow ID
|
70
|
+
workflow_id: str
|
71
|
+
# The workflow status. Must be one of ENQUEUED, PENDING, SUCCESS, ERROR, CANCELLED, or RETRIES_EXCEEDED
|
72
|
+
status: str
|
73
|
+
# The name of the workflow function
|
74
|
+
name: str
|
75
|
+
# The name of the workflow's class, if any
|
76
|
+
class_name: Optional[str]
|
77
|
+
# The name with which the workflow's class instance was configured, if any
|
78
|
+
config_name: Optional[str]
|
79
|
+
# The user who ran the workflow, if specified
|
80
|
+
authenticated_user: Optional[str]
|
81
|
+
# The role with which the workflow ran, if specified
|
82
|
+
assumed_role: Optional[str]
|
83
|
+
# All roles which the authenticated user could assume
|
84
|
+
authenticated_roles: Optional[list[str]]
|
85
|
+
# The deserialized workflow input object
|
86
|
+
input: Optional[_serialization.WorkflowInputs]
|
87
|
+
# The workflow's output, if any
|
88
|
+
output: Optional[Any] = None
|
89
|
+
# The error the workflow threw, if any
|
90
|
+
error: Optional[Exception] = None
|
91
|
+
# Workflow start time, as a Unix epoch timestamp in ms
|
92
|
+
created_at: Optional[int]
|
93
|
+
# Last time the workflow status was updated, as a Unix epoch timestamp in ms
|
94
|
+
updated_at: Optional[int]
|
95
|
+
# If this workflow was enqueued, on which queue
|
96
|
+
queue_name: Optional[str]
|
97
|
+
# The executor to most recently executed this workflow
|
98
|
+
executor_id: Optional[str]
|
99
|
+
# The application version on which this workflow was started
|
100
|
+
app_version: Optional[str]
|
101
|
+
|
102
|
+
# INTERNAL FIELDS
|
103
|
+
|
104
|
+
# The ID of the application executing this workflow
|
105
|
+
app_id: Optional[str]
|
106
|
+
# The number of times this workflow's execution has been attempted
|
107
|
+
recovery_attempts: Optional[int]
|
108
|
+
# The HTTP request that triggered the workflow, if known
|
109
|
+
request: Optional[str]
|
110
|
+
|
111
|
+
|
67
112
|
class WorkflowStatusInternal(TypedDict):
|
68
113
|
workflow_uuid: str
|
69
114
|
status: WorkflowStatuses
|
@@ -148,11 +193,6 @@ class GetQueuedWorkflowsInput(TypedDict):
|
|
148
193
|
sort_desc: Optional[bool] # Sort by created_at in DESC or ASC order
|
149
194
|
|
150
195
|
|
151
|
-
class GetWorkflowsOutput:
|
152
|
-
def __init__(self, workflow_uuids: List[str]):
|
153
|
-
self.workflow_uuids = workflow_uuids
|
154
|
-
|
155
|
-
|
156
196
|
class GetPendingWorkflowsOutput:
|
157
197
|
def __init__(self, *, workflow_uuid: str, queue_name: Optional[str] = None):
|
158
198
|
self.workflow_uuid: str = workflow_uuid
|
@@ -287,7 +327,7 @@ class SystemDatabase:
|
|
287
327
|
status: WorkflowStatusInternal,
|
288
328
|
conn: sa.Connection,
|
289
329
|
*,
|
290
|
-
max_recovery_attempts: int
|
330
|
+
max_recovery_attempts: Optional[int],
|
291
331
|
) -> WorkflowStatuses:
|
292
332
|
if self._debug_mode:
|
293
333
|
raise Exception("called insert_workflow_status in debug mode")
|
@@ -354,7 +394,11 @@ class SystemDatabase:
|
|
354
394
|
|
355
395
|
# Every time we start executing a workflow (and thus attempt to insert its status), we increment `recovery_attempts` by 1.
|
356
396
|
# When this number becomes equal to `maxRetries + 1`, we mark the workflow as `RETRIES_EXCEEDED`.
|
357
|
-
if
|
397
|
+
if (
|
398
|
+
(wf_status != "SUCCESS" and wf_status != "ERROR")
|
399
|
+
and max_recovery_attempts is not None
|
400
|
+
and recovery_attempts > max_recovery_attempts + 1
|
401
|
+
):
|
358
402
|
delete_cmd = sa.delete(SystemSchema.workflow_queue).where(
|
359
403
|
SystemSchema.workflow_queue.c.workflow_uuid
|
360
404
|
== status["workflow_uuid"]
|
@@ -702,8 +746,37 @@ class SystemDatabase:
|
|
702
746
|
)
|
703
747
|
return inputs
|
704
748
|
|
705
|
-
def get_workflows(
|
706
|
-
|
749
|
+
def get_workflows(
|
750
|
+
self, input: GetWorkflowsInput, get_request: bool = False
|
751
|
+
) -> List[WorkflowStatus]:
|
752
|
+
"""
|
753
|
+
Retrieve a list of workflows result and inputs based on the input criteria. The result is a list of external-facing workflow status objects.
|
754
|
+
"""
|
755
|
+
query = sa.select(
|
756
|
+
SystemSchema.workflow_status.c.workflow_uuid,
|
757
|
+
SystemSchema.workflow_status.c.status,
|
758
|
+
SystemSchema.workflow_status.c.name,
|
759
|
+
SystemSchema.workflow_status.c.request,
|
760
|
+
SystemSchema.workflow_status.c.recovery_attempts,
|
761
|
+
SystemSchema.workflow_status.c.config_name,
|
762
|
+
SystemSchema.workflow_status.c.class_name,
|
763
|
+
SystemSchema.workflow_status.c.authenticated_user,
|
764
|
+
SystemSchema.workflow_status.c.authenticated_roles,
|
765
|
+
SystemSchema.workflow_status.c.assumed_role,
|
766
|
+
SystemSchema.workflow_status.c.queue_name,
|
767
|
+
SystemSchema.workflow_status.c.executor_id,
|
768
|
+
SystemSchema.workflow_status.c.created_at,
|
769
|
+
SystemSchema.workflow_status.c.updated_at,
|
770
|
+
SystemSchema.workflow_status.c.application_version,
|
771
|
+
SystemSchema.workflow_status.c.application_id,
|
772
|
+
SystemSchema.workflow_inputs.c.inputs,
|
773
|
+
SystemSchema.workflow_status.c.output,
|
774
|
+
SystemSchema.workflow_status.c.error,
|
775
|
+
).join(
|
776
|
+
SystemSchema.workflow_inputs,
|
777
|
+
SystemSchema.workflow_status.c.workflow_uuid
|
778
|
+
== SystemSchema.workflow_inputs.c.workflow_uuid,
|
779
|
+
)
|
707
780
|
if input.sort_desc:
|
708
781
|
query = query.order_by(SystemSchema.workflow_status.c.created_at.desc())
|
709
782
|
else:
|
@@ -749,18 +822,76 @@ class SystemDatabase:
|
|
749
822
|
|
750
823
|
with self.engine.begin() as c:
|
751
824
|
rows = c.execute(query)
|
752
|
-
workflow_ids = [row[0] for row in rows]
|
753
825
|
|
754
|
-
|
826
|
+
infos: List[WorkflowStatus] = []
|
827
|
+
for row in rows:
|
828
|
+
info = WorkflowStatus()
|
829
|
+
info.workflow_id = row[0]
|
830
|
+
info.status = row[1]
|
831
|
+
info.name = row[2]
|
832
|
+
info.request = row[3] if get_request else None
|
833
|
+
info.recovery_attempts = row[4]
|
834
|
+
info.config_name = row[5]
|
835
|
+
info.class_name = row[6]
|
836
|
+
info.authenticated_user = row[7]
|
837
|
+
info.authenticated_roles = (
|
838
|
+
json.loads(row[8]) if row[8] is not None else None
|
839
|
+
)
|
840
|
+
info.assumed_role = row[9]
|
841
|
+
info.queue_name = row[10]
|
842
|
+
info.executor_id = row[11]
|
843
|
+
info.created_at = row[12]
|
844
|
+
info.updated_at = row[13]
|
845
|
+
info.app_version = row[14]
|
846
|
+
info.app_id = row[15]
|
847
|
+
|
848
|
+
inputs = _serialization.deserialize_args(row[16])
|
849
|
+
if inputs is not None:
|
850
|
+
info.input = inputs
|
851
|
+
if info.status == WorkflowStatusString.SUCCESS.value:
|
852
|
+
info.output = _serialization.deserialize(row[17])
|
853
|
+
elif info.status == WorkflowStatusString.ERROR.value:
|
854
|
+
info.error = _serialization.deserialize_exception(row[18])
|
855
|
+
|
856
|
+
infos.append(info)
|
857
|
+
return infos
|
755
858
|
|
756
859
|
def get_queued_workflows(
|
757
|
-
self, input: GetQueuedWorkflowsInput
|
758
|
-
) ->
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
860
|
+
self, input: GetQueuedWorkflowsInput, get_request: bool = False
|
861
|
+
) -> List[WorkflowStatus]:
|
862
|
+
"""
|
863
|
+
Retrieve a list of queued workflows result and inputs based on the input criteria. The result is a list of external-facing workflow status objects.
|
864
|
+
"""
|
865
|
+
query = sa.select(
|
866
|
+
SystemSchema.workflow_status.c.workflow_uuid,
|
867
|
+
SystemSchema.workflow_status.c.status,
|
868
|
+
SystemSchema.workflow_status.c.name,
|
869
|
+
SystemSchema.workflow_status.c.request,
|
870
|
+
SystemSchema.workflow_status.c.recovery_attempts,
|
871
|
+
SystemSchema.workflow_status.c.config_name,
|
872
|
+
SystemSchema.workflow_status.c.class_name,
|
873
|
+
SystemSchema.workflow_status.c.authenticated_user,
|
874
|
+
SystemSchema.workflow_status.c.authenticated_roles,
|
875
|
+
SystemSchema.workflow_status.c.assumed_role,
|
876
|
+
SystemSchema.workflow_status.c.queue_name,
|
877
|
+
SystemSchema.workflow_status.c.executor_id,
|
878
|
+
SystemSchema.workflow_status.c.created_at,
|
879
|
+
SystemSchema.workflow_status.c.updated_at,
|
880
|
+
SystemSchema.workflow_status.c.application_version,
|
881
|
+
SystemSchema.workflow_status.c.application_id,
|
882
|
+
SystemSchema.workflow_inputs.c.inputs,
|
883
|
+
SystemSchema.workflow_status.c.output,
|
884
|
+
SystemSchema.workflow_status.c.error,
|
885
|
+
).select_from(
|
886
|
+
SystemSchema.workflow_queue.join(
|
887
|
+
SystemSchema.workflow_status,
|
888
|
+
SystemSchema.workflow_queue.c.workflow_uuid
|
889
|
+
== SystemSchema.workflow_status.c.workflow_uuid,
|
890
|
+
).join(
|
891
|
+
SystemSchema.workflow_inputs,
|
892
|
+
SystemSchema.workflow_queue.c.workflow_uuid
|
893
|
+
== SystemSchema.workflow_inputs.c.workflow_uuid,
|
894
|
+
)
|
764
895
|
)
|
765
896
|
if input["sort_desc"]:
|
766
897
|
query = query.order_by(SystemSchema.workflow_status.c.created_at.desc())
|
@@ -797,9 +928,40 @@ class SystemDatabase:
|
|
797
928
|
|
798
929
|
with self.engine.begin() as c:
|
799
930
|
rows = c.execute(query)
|
800
|
-
workflow_uuids = [row[0] for row in rows]
|
801
931
|
|
802
|
-
|
932
|
+
infos: List[WorkflowStatus] = []
|
933
|
+
for row in rows:
|
934
|
+
info = WorkflowStatus()
|
935
|
+
info.workflow_id = row[0]
|
936
|
+
info.status = row[1]
|
937
|
+
info.name = row[2]
|
938
|
+
info.request = row[3] if get_request else None
|
939
|
+
info.recovery_attempts = row[4]
|
940
|
+
info.config_name = row[5]
|
941
|
+
info.class_name = row[6]
|
942
|
+
info.authenticated_user = row[7]
|
943
|
+
info.authenticated_roles = (
|
944
|
+
json.loads(row[8]) if row[8] is not None else None
|
945
|
+
)
|
946
|
+
info.assumed_role = row[9]
|
947
|
+
info.queue_name = row[10]
|
948
|
+
info.executor_id = row[11]
|
949
|
+
info.created_at = row[12]
|
950
|
+
info.updated_at = row[13]
|
951
|
+
info.app_version = row[14]
|
952
|
+
info.app_id = row[15]
|
953
|
+
|
954
|
+
inputs = _serialization.deserialize_args(row[16])
|
955
|
+
if inputs is not None:
|
956
|
+
info.input = inputs
|
957
|
+
if info.status == WorkflowStatusString.SUCCESS.value:
|
958
|
+
info.output = _serialization.deserialize(row[17])
|
959
|
+
elif info.status == WorkflowStatusString.ERROR.value:
|
960
|
+
info.error = _serialization.deserialize_exception(row[18])
|
961
|
+
|
962
|
+
infos.append(info)
|
963
|
+
|
964
|
+
return infos
|
803
965
|
|
804
966
|
def get_pending_workflows(
|
805
967
|
self, executor_id: str, app_version: str
|
@@ -1658,7 +1820,7 @@ class SystemDatabase:
|
|
1658
1820
|
status: WorkflowStatusInternal,
|
1659
1821
|
inputs: str,
|
1660
1822
|
*,
|
1661
|
-
max_recovery_attempts: int
|
1823
|
+
max_recovery_attempts: Optional[int],
|
1662
1824
|
) -> WorkflowStatuses:
|
1663
1825
|
"""
|
1664
1826
|
Synchronously record the status and inputs for workflows in a single transaction
|
dbos/_workflow_commands.py
CHANGED
@@ -1,62 +1,18 @@
|
|
1
|
-
import json
|
2
1
|
import uuid
|
3
|
-
from typing import
|
2
|
+
from typing import List, Optional
|
3
|
+
|
4
|
+
from dbos._error import DBOSException
|
4
5
|
|
5
|
-
from . import _serialization
|
6
6
|
from ._app_db import ApplicationDatabase
|
7
7
|
from ._sys_db import (
|
8
8
|
GetQueuedWorkflowsInput,
|
9
9
|
GetWorkflowsInput,
|
10
|
-
GetWorkflowsOutput,
|
11
10
|
StepInfo,
|
12
11
|
SystemDatabase,
|
12
|
+
WorkflowStatus,
|
13
13
|
)
|
14
14
|
|
15
15
|
|
16
|
-
class WorkflowStatus:
|
17
|
-
# The workflow ID
|
18
|
-
workflow_id: str
|
19
|
-
# The workflow status. Must be one of ENQUEUED, PENDING, SUCCESS, ERROR, CANCELLED, or RETRIES_EXCEEDED
|
20
|
-
status: str
|
21
|
-
# The name of the workflow function
|
22
|
-
name: str
|
23
|
-
# The name of the workflow's class, if any
|
24
|
-
class_name: Optional[str]
|
25
|
-
# The name with which the workflow's class instance was configured, if any
|
26
|
-
config_name: Optional[str]
|
27
|
-
# The user who ran the workflow, if specified
|
28
|
-
authenticated_user: Optional[str]
|
29
|
-
# The role with which the workflow ran, if specified
|
30
|
-
assumed_role: Optional[str]
|
31
|
-
# All roles which the authenticated user could assume
|
32
|
-
authenticated_roles: Optional[list[str]]
|
33
|
-
# The deserialized workflow input object
|
34
|
-
input: Optional[_serialization.WorkflowInputs]
|
35
|
-
# The workflow's output, if any
|
36
|
-
output: Optional[Any] = None
|
37
|
-
# The error the workflow threw, if any
|
38
|
-
error: Optional[Exception] = None
|
39
|
-
# Workflow start time, as a Unix epoch timestamp in ms
|
40
|
-
created_at: Optional[int]
|
41
|
-
# Last time the workflow status was updated, as a Unix epoch timestamp in ms
|
42
|
-
updated_at: Optional[int]
|
43
|
-
# If this workflow was enqueued, on which queue
|
44
|
-
queue_name: Optional[str]
|
45
|
-
# The executor to most recently executed this workflow
|
46
|
-
executor_id: Optional[str]
|
47
|
-
# The application version on which this workflow was started
|
48
|
-
app_version: Optional[str]
|
49
|
-
|
50
|
-
# INTERNAL FIELDS
|
51
|
-
|
52
|
-
# The ID of the application executing this workflow
|
53
|
-
app_id: Optional[str]
|
54
|
-
# The number of times this workflow's execution has been attempted
|
55
|
-
recovery_attempts: Optional[int]
|
56
|
-
# The HTTP request that triggered the workflow, if known
|
57
|
-
request: Optional[str]
|
58
|
-
|
59
|
-
|
60
16
|
def list_workflows(
|
61
17
|
sys_db: SystemDatabase,
|
62
18
|
*,
|
@@ -86,12 +42,8 @@ def list_workflows(
|
|
86
42
|
input.sort_desc = sort_desc
|
87
43
|
input.workflow_id_prefix = workflow_id_prefix
|
88
44
|
|
89
|
-
|
90
|
-
|
91
|
-
for workflow_id in output.workflow_uuids:
|
92
|
-
info = get_workflow(sys_db, workflow_id, request) # Call the method for each ID
|
93
|
-
if info is not None:
|
94
|
-
infos.append(info)
|
45
|
+
infos: List[WorkflowStatus] = sys_db.get_workflows(input, request)
|
46
|
+
|
95
47
|
return infos
|
96
48
|
|
97
49
|
|
@@ -118,63 +70,22 @@ def list_queued_workflows(
|
|
118
70
|
"offset": offset,
|
119
71
|
"sort_desc": sort_desc,
|
120
72
|
}
|
121
|
-
|
122
|
-
infos: List[WorkflowStatus] =
|
123
|
-
for workflow_id in output.workflow_uuids:
|
124
|
-
info = get_workflow(sys_db, workflow_id, request) # Call the method for each ID
|
125
|
-
if info is not None:
|
126
|
-
infos.append(info)
|
73
|
+
|
74
|
+
infos: List[WorkflowStatus] = sys_db.get_queued_workflows(input, request)
|
127
75
|
return infos
|
128
76
|
|
129
77
|
|
130
78
|
def get_workflow(
|
131
79
|
sys_db: SystemDatabase, workflow_id: str, get_request: bool
|
132
80
|
) -> Optional[WorkflowStatus]:
|
81
|
+
input = GetWorkflowsInput()
|
82
|
+
input.workflow_ids = [workflow_id]
|
133
83
|
|
134
|
-
|
135
|
-
if
|
84
|
+
infos: List[WorkflowStatus] = sys_db.get_workflows(input, get_request)
|
85
|
+
if not infos:
|
136
86
|
return None
|
137
87
|
|
138
|
-
|
139
|
-
|
140
|
-
info.workflow_id = workflow_id
|
141
|
-
info.status = internal_status["status"]
|
142
|
-
info.name = internal_status["name"]
|
143
|
-
info.class_name = internal_status["class_name"]
|
144
|
-
info.config_name = internal_status["config_name"]
|
145
|
-
info.authenticated_user = internal_status["authenticated_user"]
|
146
|
-
info.assumed_role = internal_status["assumed_role"]
|
147
|
-
info.authenticated_roles = (
|
148
|
-
json.loads(internal_status["authenticated_roles"])
|
149
|
-
if internal_status["authenticated_roles"] is not None
|
150
|
-
else None
|
151
|
-
)
|
152
|
-
info.request = internal_status["request"]
|
153
|
-
info.created_at = internal_status["created_at"]
|
154
|
-
info.updated_at = internal_status["updated_at"]
|
155
|
-
info.queue_name = internal_status["queue_name"]
|
156
|
-
info.executor_id = internal_status["executor_id"]
|
157
|
-
info.app_version = internal_status["app_version"]
|
158
|
-
info.app_id = internal_status["app_id"]
|
159
|
-
info.recovery_attempts = internal_status["recovery_attempts"]
|
160
|
-
|
161
|
-
input_data = sys_db.get_workflow_inputs(workflow_id)
|
162
|
-
if input_data is not None:
|
163
|
-
info.input = input_data
|
164
|
-
|
165
|
-
if internal_status.get("status") == "SUCCESS":
|
166
|
-
result = sys_db.await_workflow_result(workflow_id)
|
167
|
-
info.output = result
|
168
|
-
elif internal_status.get("status") == "ERROR":
|
169
|
-
try:
|
170
|
-
sys_db.await_workflow_result(workflow_id)
|
171
|
-
except Exception as e:
|
172
|
-
info.error = e
|
173
|
-
|
174
|
-
if not get_request:
|
175
|
-
info.request = None
|
176
|
-
|
177
|
-
return info
|
88
|
+
return infos[0]
|
178
89
|
|
179
90
|
|
180
91
|
def list_workflow_steps(
|
@@ -185,3 +96,25 @@ def list_workflow_steps(
|
|
185
96
|
merged_steps = steps + transactions
|
186
97
|
merged_steps.sort(key=lambda step: step["function_id"])
|
187
98
|
return merged_steps
|
99
|
+
|
100
|
+
|
101
|
+
def fork_workflow(
|
102
|
+
sys_db: SystemDatabase,
|
103
|
+
app_db: ApplicationDatabase,
|
104
|
+
workflow_id: str,
|
105
|
+
start_step: int,
|
106
|
+
) -> str:
|
107
|
+
def get_max_function_id(workflow_uuid: str) -> int:
|
108
|
+
max_transactions = app_db.get_max_function_id(workflow_uuid) or 0
|
109
|
+
max_operations = sys_db.get_max_function_id(workflow_uuid) or 0
|
110
|
+
return max(max_transactions, max_operations)
|
111
|
+
|
112
|
+
max_function_id = get_max_function_id(workflow_id)
|
113
|
+
if max_function_id > 0 and start_step > max_function_id:
|
114
|
+
raise DBOSException(
|
115
|
+
f"Cannot fork workflow {workflow_id} from step {start_step}. The workflow has {max_function_id} steps."
|
116
|
+
)
|
117
|
+
forked_workflow_id = str(uuid.uuid4())
|
118
|
+
app_db.clone_workflow_transactions(workflow_id, forked_workflow_id, start_step)
|
119
|
+
sys_db.fork_workflow(workflow_id, forked_workflow_id, start_step)
|
120
|
+
return forked_workflow_id
|
@@ -1,19 +1,19 @@
|
|
1
|
-
dbos-0.26.
|
2
|
-
dbos-0.26.
|
3
|
-
dbos-0.26.
|
4
|
-
dbos-0.26.
|
5
|
-
dbos/__init__.py,sha256=
|
1
|
+
dbos-0.26.0a21.dist-info/METADATA,sha256=6JPLTUn5uCaKpHI_sEis2zJWOrNqsRUIQ2_4h7ZzWfw,5554
|
2
|
+
dbos-0.26.0a21.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
|
3
|
+
dbos-0.26.0a21.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
|
4
|
+
dbos-0.26.0a21.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
|
5
|
+
dbos/__init__.py,sha256=VoGS7H9GVtNAnD2S4zseIEioS1dNIJXRovQ4oHlg8og,842
|
6
6
|
dbos/__main__.py,sha256=G7Exn-MhGrVJVDbgNlpzhfh8WMX_72t3_oJaFT9Lmt8,653
|
7
7
|
dbos/_admin_server.py,sha256=RrbABfR1D3p9c_QLrCSrgFuYce6FKi0fjMRIYLjO_Y8,9038
|
8
|
-
dbos/_app_db.py,sha256=
|
8
|
+
dbos/_app_db.py,sha256=obNlgC9IZ20y8tqQeA1q4TjceG3jBFalxz70ieDOWCA,11332
|
9
9
|
dbos/_classproperty.py,sha256=f0X-_BySzn3yFDRKB2JpCbLYQ9tLwt1XftfshvY7CBs,626
|
10
|
-
dbos/_client.py,sha256=
|
10
|
+
dbos/_client.py,sha256=S3tejQ7xAJ9wjo1PhQ0P3UYuloDOdZqXsQwE4YjAQ8s,12124
|
11
11
|
dbos/_conductor/conductor.py,sha256=HYzVL29IMMrs2Mnms_7cHJynCnmmEN5SDQOMjzn3UoU,16840
|
12
|
-
dbos/_conductor/protocol.py,sha256=
|
12
|
+
dbos/_conductor/protocol.py,sha256=zEKIuOQdIaSduNqfZKpo8PSD9_1oNpKIPnBNCu3RUyE,6681
|
13
13
|
dbos/_context.py,sha256=I8sLkdKTTkZEz7wG-MjynaQB6XEF2bLXuwNksiauP7w,19430
|
14
|
-
dbos/_core.py,sha256=
|
14
|
+
dbos/_core.py,sha256=SecObOKLjNinNAXDcYVMVUURHcoaPe0js-axLMMNwqY,45098
|
15
15
|
dbos/_croniter.py,sha256=XHAyUyibs_59sJQfSNWkP7rqQY6_XrlfuuCxk4jYqek,47559
|
16
|
-
dbos/_dbos.py,sha256=
|
16
|
+
dbos/_dbos.py,sha256=bbio_FjBfU__Zk1BFegfS16IrPPejFxOKm5rUg5nW1o,47185
|
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
|
@@ -37,7 +37,7 @@ dbos/_migrations/versions/f4b9b32ba814_functionname_childid_op_outputs.py,sha256
|
|
37
37
|
dbos/_outcome.py,sha256=EXxBg4jXCVJsByDQ1VOCIedmbeq_03S6d-p1vqQrLFU,6810
|
38
38
|
dbos/_queue.py,sha256=l0g_CXJbxEmftCA9yhy-cyaR_sddfQSCfm-5XgIWzqU,3397
|
39
39
|
dbos/_recovery.py,sha256=98Py7icfytyIELJ54gIsdvmURBvTb0HmWaxEAuYL0dc,2546
|
40
|
-
dbos/_registrations.py,sha256=
|
40
|
+
dbos/_registrations.py,sha256=EZzG3ZfYmWA2bHX2hpnSIQ3PTi3-cXsvbcmXjyOusMk,7302
|
41
41
|
dbos/_request.py,sha256=cX1B3Atlh160phgS35gF1VEEV4pD126c9F3BDgBmxZU,929
|
42
42
|
dbos/_roles.py,sha256=iOsgmIAf1XVzxs3gYWdGRe1B880YfOw5fpU7Jwx8_A8,2271
|
43
43
|
dbos/_scheduler.py,sha256=SR1oRZRcVzYsj-JauV2LA8JtwTkt8mru7qf6H1AzQ1U,2027
|
@@ -45,7 +45,7 @@ dbos/_schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
dbos/_schemas/application_database.py,sha256=SypAS9l9EsaBHFn9FR8jmnqt01M74d9AF1AMa4m2hhI,1040
|
46
46
|
dbos/_schemas/system_database.py,sha256=W9eSpL7SZzQkxcEZ4W07BOcwkkDr35b9oCjUOgfHWek,5336
|
47
47
|
dbos/_serialization.py,sha256=YCYv0qKAwAZ1djZisBC7khvKqG-5OcIv9t9EC5PFIog,1743
|
48
|
-
dbos/_sys_db.py,sha256=
|
48
|
+
dbos/_sys_db.py,sha256=M3BVJVhG0YXkLhw5axSrKjBN1AOS3KmvgWEYn2l94pw,78203
|
49
49
|
dbos/_templates/dbos-db-starter/README.md,sha256=GhxhBj42wjTt1fWEtwNriHbJuKb66Vzu89G4pxNHw2g,930
|
50
50
|
dbos/_templates/dbos-db-starter/__package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
51
51
|
dbos/_templates/dbos-db-starter/__package/main.py,sha256=nJMN3ZD2lmwg4Dcgmiwqc-tQGuCJuJal2Xl85iA277U,2453
|
@@ -58,11 +58,11 @@ dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py,sh
|
|
58
58
|
dbos/_templates/dbos-db-starter/start_postgres_docker.py,sha256=lQVLlYO5YkhGPEgPqwGc7Y8uDKse9HsWv5fynJEFJHM,1681
|
59
59
|
dbos/_tracer.py,sha256=dFDSFlta-rfA3-ahIRLYwnnoAOmlavdxAGllqwFgnCA,2440
|
60
60
|
dbos/_utils.py,sha256=nFRUHzVjXG5AusF85AlYHikj63Tzi-kQm992ihsrAxA,201
|
61
|
-
dbos/_workflow_commands.py,sha256=
|
61
|
+
dbos/_workflow_commands.py,sha256=7wyxTfIyh2IVIqlkaTr8CMBq8yxWP3Hhddyv1YJY8zE,3576
|
62
62
|
dbos/cli/_github_init.py,sha256=Y_bDF9gfO2jB1id4FV5h1oIxEJRWyqVjhb7bNEa5nQ0,3224
|
63
63
|
dbos/cli/_template_init.py,sha256=-WW3kbq0W_Tq4WbMqb1UGJG3xvJb3woEY5VspG95Srk,2857
|
64
64
|
dbos/cli/cli.py,sha256=1qCTs__A9LOEfU44XZ6TufwmRwe68ZEwbWEPli3vnVM,17873
|
65
65
|
dbos/dbos-config.schema.json,sha256=i7jcxXqByKq0Jzv3nAUavONtj03vTwj6vWP4ylmBr8o,5694
|
66
66
|
dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
|
67
67
|
version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
|
68
|
-
dbos-0.26.
|
68
|
+
dbos-0.26.0a21.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|