dbos 1.8.0a5__py3-none-any.whl → 1.9.0a1__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 +25 -53
- dbos/_error.py +5 -5
- dbos/_sys_db.py +12 -7
- dbos/cli/cli.py +2 -2
- {dbos-1.8.0a5.dist-info → dbos-1.9.0a1.dist-info}/METADATA +1 -1
- {dbos-1.8.0a5.dist-info → dbos-1.9.0a1.dist-info}/RECORD +9 -9
- {dbos-1.8.0a5.dist-info → dbos-1.9.0a1.dist-info}/WHEEL +0 -0
- {dbos-1.8.0a5.dist-info → dbos-1.9.0a1.dist-info}/entry_points.txt +0 -0
- {dbos-1.8.0a5.dist-info → dbos-1.9.0a1.dist-info}/licenses/LICENSE +0 -0
dbos/_dbos.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
import atexit
|
|
5
4
|
import hashlib
|
|
6
5
|
import inspect
|
|
7
6
|
import os
|
|
@@ -1219,39 +1218,40 @@ class DBOS:
|
|
|
1219
1218
|
return rv
|
|
1220
1219
|
|
|
1221
1220
|
@classproperty
|
|
1222
|
-
def workflow_id(cls) -> str:
|
|
1223
|
-
"""Return the
|
|
1224
|
-
ctx =
|
|
1225
|
-
|
|
1226
|
-
ctx.
|
|
1227
|
-
|
|
1228
|
-
|
|
1221
|
+
def workflow_id(cls) -> Optional[str]:
|
|
1222
|
+
"""Return the ID of the currently executing workflow. If a workflow is not executing, return None."""
|
|
1223
|
+
ctx = get_local_dbos_context()
|
|
1224
|
+
if ctx and ctx.is_within_workflow():
|
|
1225
|
+
return ctx.workflow_id
|
|
1226
|
+
else:
|
|
1227
|
+
return None
|
|
1229
1228
|
|
|
1230
1229
|
@classproperty
|
|
1231
|
-
def step_id(cls) -> int:
|
|
1232
|
-
"""Return the step ID for the currently executing step. This is a unique identifier of the current step within the workflow."""
|
|
1233
|
-
ctx =
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1230
|
+
def step_id(cls) -> Optional[int]:
|
|
1231
|
+
"""Return the step ID for the currently executing step. This is a unique identifier of the current step within the workflow. If a step is not currently executing, return None."""
|
|
1232
|
+
ctx = get_local_dbos_context()
|
|
1233
|
+
if ctx and (ctx.is_step() or ctx.is_transaction()):
|
|
1234
|
+
return ctx.function_id
|
|
1235
|
+
else:
|
|
1236
|
+
return None
|
|
1238
1237
|
|
|
1239
1238
|
@classproperty
|
|
1240
|
-
def step_status(cls) -> StepStatus:
|
|
1241
|
-
"""Return the status of the currently executing step."""
|
|
1242
|
-
ctx =
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1239
|
+
def step_status(cls) -> Optional[StepStatus]:
|
|
1240
|
+
"""Return the status of the currently executing step. If a step is not currently executing, return None."""
|
|
1241
|
+
ctx = get_local_dbos_context()
|
|
1242
|
+
if ctx and ctx.is_step():
|
|
1243
|
+
return ctx.step_status
|
|
1244
|
+
else:
|
|
1245
|
+
return None
|
|
1246
1246
|
|
|
1247
1247
|
@classproperty
|
|
1248
1248
|
def parent_workflow_id(cls) -> str:
|
|
1249
1249
|
"""
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
`parent_workflow_id` must be accessed from within a workflow function.
|
|
1250
|
+
This method is deprecated and should not be used.
|
|
1253
1251
|
"""
|
|
1254
|
-
|
|
1252
|
+
dbos_logger.warning(
|
|
1253
|
+
"DBOS.parent_workflow_id is deprecated and should not be used"
|
|
1254
|
+
)
|
|
1255
1255
|
ctx = assert_current_dbos_context()
|
|
1256
1256
|
assert (
|
|
1257
1257
|
ctx.is_within_workflow()
|
|
@@ -1376,31 +1376,3 @@ class DBOSConfiguredInstance:
|
|
|
1376
1376
|
def __init__(self, config_name: str) -> None:
|
|
1377
1377
|
self.config_name = config_name
|
|
1378
1378
|
DBOS.register_instance(self)
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
# Apps that import DBOS probably don't exit. If they do, let's see if
|
|
1382
|
-
# it looks like startup was abandoned or a call was forgotten...
|
|
1383
|
-
def _dbos_exit_hook() -> None:
|
|
1384
|
-
if _dbos_global_registry is None:
|
|
1385
|
-
# Probably used as or for a support module
|
|
1386
|
-
return
|
|
1387
|
-
if _dbos_global_instance is None:
|
|
1388
|
-
print("DBOS exiting; functions were registered but DBOS() was not called")
|
|
1389
|
-
dbos_logger.warning(
|
|
1390
|
-
"DBOS exiting; functions were registered but DBOS() was not called"
|
|
1391
|
-
)
|
|
1392
|
-
return
|
|
1393
|
-
if not _dbos_global_instance._launched:
|
|
1394
|
-
if _dbos_global_instance.fastapi is not None:
|
|
1395
|
-
# FastAPI lifespan middleware will call launch/destroy, so we can ignore this.
|
|
1396
|
-
# This is likely to happen during fastapi dev runs, where the reloader loads the module multiple times.
|
|
1397
|
-
return
|
|
1398
|
-
print("DBOS exiting; DBOS exists but launch() was not called")
|
|
1399
|
-
dbos_logger.warning("DBOS exiting; DBOS exists but launch() was not called")
|
|
1400
|
-
return
|
|
1401
|
-
# If we get here, we're exiting normally
|
|
1402
|
-
_dbos_global_instance.destroy()
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
# Register the exit hook
|
|
1406
|
-
atexit.register(_dbos_exit_hook)
|
dbos/_error.py
CHANGED
|
@@ -55,7 +55,7 @@ class DBOSErrorCode(Enum):
|
|
|
55
55
|
InitializationError = 3
|
|
56
56
|
WorkflowFunctionNotFound = 4
|
|
57
57
|
NonExistentWorkflowError = 5
|
|
58
|
-
|
|
58
|
+
MaxRecoveryAttemptsExceeded = 6
|
|
59
59
|
MaxStepRetriesExceeded = 7
|
|
60
60
|
NotAuthorized = 8
|
|
61
61
|
ConflictingWorkflowError = 9
|
|
@@ -121,13 +121,13 @@ class DBOSNonExistentWorkflowError(DBOSException):
|
|
|
121
121
|
)
|
|
122
122
|
|
|
123
123
|
|
|
124
|
-
class
|
|
125
|
-
"""Exception raised when a workflow
|
|
124
|
+
class MaxRecoveryAttemptsExceededError(DBOSException):
|
|
125
|
+
"""Exception raised when a workflow exceeds its max recovery attempts."""
|
|
126
126
|
|
|
127
127
|
def __init__(self, wf_id: str, max_retries: int):
|
|
128
128
|
super().__init__(
|
|
129
|
-
f"Workflow {wf_id} has
|
|
130
|
-
dbos_error_code=DBOSErrorCode.
|
|
129
|
+
f"Workflow {wf_id} has exceeded its maximum of {max_retries} execution or recovery attempts. Further attempts to execute or recover it will fail. See documentation for details: https://docs.dbos.dev/python/reference/decorators",
|
|
130
|
+
dbos_error_code=DBOSErrorCode.MaxRecoveryAttemptsExceeded.value,
|
|
131
131
|
)
|
|
132
132
|
|
|
133
133
|
|
dbos/_sys_db.py
CHANGED
|
@@ -37,12 +37,12 @@ from ._context import get_local_dbos_context
|
|
|
37
37
|
from ._error import (
|
|
38
38
|
DBOSAwaitedWorkflowCancelledError,
|
|
39
39
|
DBOSConflictingWorkflowError,
|
|
40
|
-
DBOSDeadLetterQueueError,
|
|
41
40
|
DBOSNonExistentWorkflowError,
|
|
42
41
|
DBOSQueueDeduplicatedError,
|
|
43
42
|
DBOSUnexpectedStepError,
|
|
44
43
|
DBOSWorkflowCancelledError,
|
|
45
44
|
DBOSWorkflowConflictIDError,
|
|
45
|
+
MaxRecoveryAttemptsExceededError,
|
|
46
46
|
)
|
|
47
47
|
from ._logger import dbos_logger
|
|
48
48
|
from ._schemas.system_database import SystemSchema
|
|
@@ -57,20 +57,25 @@ class WorkflowStatusString(Enum):
|
|
|
57
57
|
PENDING = "PENDING"
|
|
58
58
|
SUCCESS = "SUCCESS"
|
|
59
59
|
ERROR = "ERROR"
|
|
60
|
-
|
|
60
|
+
MAX_RECOVERY_ATTEMPTS_EXCEEDED = "MAX_RECOVERY_ATTEMPTS_EXCEEDED"
|
|
61
61
|
CANCELLED = "CANCELLED"
|
|
62
62
|
ENQUEUED = "ENQUEUED"
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
WorkflowStatuses = Literal[
|
|
66
|
-
"PENDING",
|
|
66
|
+
"PENDING",
|
|
67
|
+
"SUCCESS",
|
|
68
|
+
"ERROR",
|
|
69
|
+
"MAX_RECOVERY_ATTEMPTS_EXCEEDED",
|
|
70
|
+
"CANCELLED",
|
|
71
|
+
"ENQUEUED",
|
|
67
72
|
]
|
|
68
73
|
|
|
69
74
|
|
|
70
75
|
class WorkflowStatus:
|
|
71
76
|
# The workflow ID
|
|
72
77
|
workflow_id: str
|
|
73
|
-
# The workflow status. Must be one of ENQUEUED, PENDING, SUCCESS, ERROR, CANCELLED, or
|
|
78
|
+
# The workflow status. Must be one of ENQUEUED, PENDING, SUCCESS, ERROR, CANCELLED, or MAX_RECOVERY_ATTEMPTS_EXCEEDED
|
|
74
79
|
status: str
|
|
75
80
|
# The name of the workflow function
|
|
76
81
|
name: str
|
|
@@ -515,7 +520,7 @@ class SystemDatabase:
|
|
|
515
520
|
raise DBOSConflictingWorkflowError(status["workflow_uuid"], err_msg)
|
|
516
521
|
|
|
517
522
|
# Every time we start executing a workflow (and thus attempt to insert its status), we increment `recovery_attempts` by 1.
|
|
518
|
-
# When this number becomes equal to `maxRetries + 1`, we mark the workflow as `
|
|
523
|
+
# When this number becomes equal to `maxRetries + 1`, we mark the workflow as `MAX_RECOVERY_ATTEMPTS_EXCEEDED`.
|
|
519
524
|
if (
|
|
520
525
|
(wf_status != "SUCCESS" and wf_status != "ERROR")
|
|
521
526
|
and max_recovery_attempts is not None
|
|
@@ -532,7 +537,7 @@ class SystemDatabase:
|
|
|
532
537
|
== WorkflowStatusString.PENDING.value
|
|
533
538
|
)
|
|
534
539
|
.values(
|
|
535
|
-
status=WorkflowStatusString.
|
|
540
|
+
status=WorkflowStatusString.MAX_RECOVERY_ATTEMPTS_EXCEEDED.value,
|
|
536
541
|
deduplication_id=None,
|
|
537
542
|
started_at_epoch_ms=None,
|
|
538
543
|
queue_name=None,
|
|
@@ -541,7 +546,7 @@ class SystemDatabase:
|
|
|
541
546
|
conn.execute(dlq_cmd)
|
|
542
547
|
# Need to commit here because we're throwing an exception
|
|
543
548
|
conn.commit()
|
|
544
|
-
raise
|
|
549
|
+
raise MaxRecoveryAttemptsExceededError(
|
|
545
550
|
status["workflow_uuid"], max_recovery_attempts
|
|
546
551
|
)
|
|
547
552
|
|
dbos/cli/cli.py
CHANGED
|
@@ -450,7 +450,7 @@ def list(
|
|
|
450
450
|
typer.Option(
|
|
451
451
|
"--status",
|
|
452
452
|
"-S",
|
|
453
|
-
help="Retrieve workflows with this status (PENDING, SUCCESS, ERROR,
|
|
453
|
+
help="Retrieve workflows with this status (PENDING, SUCCESS, ERROR, ENQUEUED, CANCELLED, or MAX_RECOVERY_ATTEMPTS_EXCEEDED)",
|
|
454
454
|
),
|
|
455
455
|
] = None,
|
|
456
456
|
appversion: Annotated[
|
|
@@ -657,7 +657,7 @@ def list_queue(
|
|
|
657
657
|
typer.Option(
|
|
658
658
|
"--status",
|
|
659
659
|
"-S",
|
|
660
|
-
help="Retrieve functions with this status (PENDING, SUCCESS, ERROR,
|
|
660
|
+
help="Retrieve functions with this status (PENDING, SUCCESS, ERROR, ENQUEUED, CANCELLED, or MAX_RECOVERY_ATTEMPTS_EXCEEDED)",
|
|
661
661
|
),
|
|
662
662
|
] = None,
|
|
663
663
|
queue_name: Annotated[
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
dbos-1.
|
|
2
|
-
dbos-1.
|
|
3
|
-
dbos-1.
|
|
4
|
-
dbos-1.
|
|
1
|
+
dbos-1.9.0a1.dist-info/METADATA,sha256=lm_ZZF0bWGuy1sNS_bqk5-XzNFqVlk83gpNvH5F2CMU,13267
|
|
2
|
+
dbos-1.9.0a1.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
dbos-1.9.0a1.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
|
|
4
|
+
dbos-1.9.0a1.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
|
|
5
5
|
dbos/__init__.py,sha256=NssPCubaBxdiKarOWa-wViz1hdJSkmBGcpLX_gQ4NeA,891
|
|
6
6
|
dbos/__main__.py,sha256=G7Exn-MhGrVJVDbgNlpzhfh8WMX_72t3_oJaFT9Lmt8,653
|
|
7
7
|
dbos/_admin_server.py,sha256=e8ELhcDWqR3_PNobnNgUvLGh5lzZq0yFSF6dvtzoQRI,16267
|
|
@@ -13,11 +13,11 @@ dbos/_conductor/protocol.py,sha256=q3rgLxINFtWFigdOONc-4gX4vn66UmMlJQD6Kj8LnL4,7
|
|
|
13
13
|
dbos/_context.py,sha256=0vFtLAk3WF5BQYIYNFImDRBppKO2CTKOSy51zQC-Cu8,25723
|
|
14
14
|
dbos/_core.py,sha256=kRY2PXVryfpwjbOCmgzPA_-qNsFmRMLi-CxYCnyp1V8,49495
|
|
15
15
|
dbos/_croniter.py,sha256=XHAyUyibs_59sJQfSNWkP7rqQY6_XrlfuuCxk4jYqek,47559
|
|
16
|
-
dbos/_dbos.py,sha256=
|
|
16
|
+
dbos/_dbos.py,sha256=LqE8ej317diZ5JjrXhndLwDr40E1Aw3SK1YPxC8-t3k,50902
|
|
17
17
|
dbos/_dbos_config.py,sha256=TWIbGCWl_8o3l0Y2IzrL1q9mTYl_vVeZDjYJMDXCPVU,21676
|
|
18
18
|
dbos/_debug.py,sha256=99j2SChWmCPAlZoDmjsJGe77tpU2LEa8E2TtLAnnh7o,1831
|
|
19
19
|
dbos/_docker_pg_helper.py,sha256=tLJXWqZ4S-ExcaPnxg_i6cVxL6ZxrYlZjaGsklY-s2I,6115
|
|
20
|
-
dbos/_error.py,sha256=
|
|
20
|
+
dbos/_error.py,sha256=2_2ve3qN0BLhFWMmd3aD9At54tIMCeh8TqHtVcEEVQo,8705
|
|
21
21
|
dbos/_event_loop.py,sha256=cvaFN9-II3MsHEOq8QoICc_8qSKrjikMlLfuhC3Y8Dk,2923
|
|
22
22
|
dbos/_fastapi.py,sha256=T7YlVY77ASqyTqq0aAPclZ9YzlXdGTT0lEYSwSgt1EE,3151
|
|
23
23
|
dbos/_flask.py,sha256=Npnakt-a3W5OykONFRkDRnumaDhTQmA0NPdUCGRYKXE,1652
|
|
@@ -49,7 +49,7 @@ dbos/_schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
49
49
|
dbos/_schemas/application_database.py,sha256=SypAS9l9EsaBHFn9FR8jmnqt01M74d9AF1AMa4m2hhI,1040
|
|
50
50
|
dbos/_schemas/system_database.py,sha256=rbFKggONdvvbb45InvGz0TM6a7c-Ux9dcaL-h_7Z7pU,4438
|
|
51
51
|
dbos/_serialization.py,sha256=bWuwhXSQcGmiazvhJHA5gwhrRWxtmFmcCFQSDJnqqkU,3666
|
|
52
|
-
dbos/_sys_db.py,sha256=
|
|
52
|
+
dbos/_sys_db.py,sha256=0GAWwxxelTxukYHQIwLr9JOlwy0vENkxbyGcfnv8_Ko,81321
|
|
53
53
|
dbos/_templates/dbos-db-starter/README.md,sha256=GhxhBj42wjTt1fWEtwNriHbJuKb66Vzu89G4pxNHw2g,930
|
|
54
54
|
dbos/_templates/dbos-db-starter/__package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
55
55
|
dbos/_templates/dbos-db-starter/__package/main.py.dbos,sha256=aQnBPSSQpkB8ERfhf7gB7P9tsU6OPKhZscfeh0yiaD8,2702
|
|
@@ -65,8 +65,8 @@ dbos/_utils.py,sha256=uywq1QrjMwy17btjxW4bES49povlQwYwYbvKwMT6C2U,1575
|
|
|
65
65
|
dbos/_workflow_commands.py,sha256=EmmAaQfRWeOZm_WPTznuU-O3he3jiSzzT9VpYrhxugE,4835
|
|
66
66
|
dbos/cli/_github_init.py,sha256=Y_bDF9gfO2jB1id4FV5h1oIxEJRWyqVjhb7bNEa5nQ0,3224
|
|
67
67
|
dbos/cli/_template_init.py,sha256=7JBcpMqP1r2mfCnvWatu33z8ctEGHJarlZYKgB83cXE,2972
|
|
68
|
-
dbos/cli/cli.py,sha256=
|
|
68
|
+
dbos/cli/cli.py,sha256=TwiaWr5zZrXOyhgv7OgkWzVA3y8znCj2L6i0sb91--0,22122
|
|
69
69
|
dbos/dbos-config.schema.json,sha256=CjaspeYmOkx6Ip_pcxtmfXJTn_YGdSx_0pcPBF7KZmo,6060
|
|
70
70
|
dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
|
|
71
71
|
version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
|
|
72
|
-
dbos-1.
|
|
72
|
+
dbos-1.9.0a1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|