dbos 0.25.0a16__py3-none-any.whl → 0.26.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.
- dbos/__init__.py +1 -2
- dbos/_admin_server.py +56 -6
- dbos/_app_db.py +135 -8
- dbos/_client.py +175 -15
- dbos/_conductor/conductor.py +2 -1
- dbos/_conductor/protocol.py +1 -2
- dbos/_context.py +66 -2
- dbos/_core.py +130 -76
- dbos/_dbos.py +155 -107
- dbos/_dbos_config.py +53 -67
- dbos/_debug.py +1 -1
- dbos/_docker_pg_helper.py +191 -0
- dbos/_error.py +61 -15
- dbos/_event_loop.py +67 -0
- dbos/_kafka.py +1 -1
- dbos/_migrations/versions/83f3732ae8e7_workflow_timeout.py +44 -0
- dbos/_queue.py +2 -1
- dbos/_recovery.py +1 -1
- dbos/_registrations.py +20 -5
- dbos/_scheduler.py +1 -1
- dbos/_schemas/application_database.py +1 -0
- dbos/_schemas/system_database.py +3 -1
- dbos/_sys_db.py +533 -130
- dbos/_utils.py +2 -0
- dbos/_workflow_commands.py +49 -104
- dbos/cli/cli.py +70 -4
- dbos/dbos-config.schema.json +26 -21
- {dbos-0.25.0a16.dist-info → dbos-0.26.0.dist-info}/METADATA +1 -1
- {dbos-0.25.0a16.dist-info → dbos-0.26.0.dist-info}/RECORD +32 -33
- {dbos-0.25.0a16.dist-info → dbos-0.26.0.dist-info}/WHEEL +1 -1
- dbos/_cloudutils/authentication.py +0 -163
- dbos/_cloudutils/cloudutils.py +0 -254
- dbos/_cloudutils/databases.py +0 -241
- dbos/_db_wizard.py +0 -220
- {dbos-0.25.0a16.dist-info → dbos-0.26.0.dist-info}/entry_points.txt +0 -0
- {dbos-0.25.0a16.dist-info → dbos-0.26.0.dist-info}/licenses/LICENSE +0 -0
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,14 +30,10 @@ 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
|
-
from dbos.
|
|
37
|
-
from dbos.
|
|
38
|
-
|
|
39
|
-
list_queued_workflows,
|
|
40
|
-
list_workflows,
|
|
41
|
-
)
|
|
34
|
+
from dbos._sys_db import WorkflowStatus
|
|
35
|
+
from dbos._utils import INTERNAL_QUEUE_NAME, GlobalParams
|
|
36
|
+
from dbos._workflow_commands import fork_workflow, list_queued_workflows, list_workflows
|
|
42
37
|
|
|
43
38
|
from ._classproperty import classproperty
|
|
44
39
|
from ._core import (
|
|
@@ -62,13 +57,14 @@ from ._recovery import recover_pending_workflows, startup_recovery_thread
|
|
|
62
57
|
from ._registrations import (
|
|
63
58
|
DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
|
64
59
|
DBOSClassInfo,
|
|
60
|
+
_class_fqn,
|
|
65
61
|
get_or_create_class_info,
|
|
66
62
|
set_dbos_func_name,
|
|
67
63
|
set_temp_workflow_type,
|
|
68
64
|
)
|
|
69
65
|
from ._roles import default_required_roles, required_roles
|
|
70
66
|
from ._scheduler import ScheduledWorkflow, scheduled
|
|
71
|
-
from ._sys_db import reset_system_database
|
|
67
|
+
from ._sys_db import StepInfo, WorkflowStatus, reset_system_database
|
|
72
68
|
from ._tracer import dbos_tracer
|
|
73
69
|
|
|
74
70
|
if TYPE_CHECKING:
|
|
@@ -111,9 +107,10 @@ from ._error import (
|
|
|
111
107
|
DBOSException,
|
|
112
108
|
DBOSNonExistentWorkflowError,
|
|
113
109
|
)
|
|
110
|
+
from ._event_loop import BackgroundEventLoop
|
|
114
111
|
from ._logger import add_otlp_to_all_loggers, config_logger, dbos_logger, init_logger
|
|
115
112
|
from ._sys_db import SystemDatabase
|
|
116
|
-
from ._workflow_commands import
|
|
113
|
+
from ._workflow_commands import get_workflow, list_workflow_steps
|
|
117
114
|
|
|
118
115
|
# Most DBOS functions are just any callable F, so decorators / wrappers work on F
|
|
119
116
|
# There are cases where the parameters P and return value R should be separate
|
|
@@ -166,25 +163,32 @@ class DBOSRegistry:
|
|
|
166
163
|
self.pollers: list[RegisteredJob] = []
|
|
167
164
|
self.dbos: Optional[DBOS] = None
|
|
168
165
|
self.config: Optional[ConfigFile] = None
|
|
169
|
-
self.workflow_cancelled_map: dict[str, bool] = {}
|
|
170
166
|
|
|
171
167
|
def register_wf_function(self, name: str, wrapped_func: F, functype: str) -> None:
|
|
172
168
|
if name in self.function_type_map:
|
|
173
169
|
if self.function_type_map[name] != functype:
|
|
174
170
|
raise DBOSConflictingRegistrationError(name)
|
|
171
|
+
if name != TEMP_SEND_WF_NAME:
|
|
172
|
+
# Remove the `<temp>` prefix from the function name to avoid confusion
|
|
173
|
+
truncated_name = name.replace("<temp>.", "")
|
|
174
|
+
dbos_logger.warning(
|
|
175
|
+
f"Duplicate registration of function '{truncated_name}'. A function named '{truncated_name}' has already been registered with DBOS. All functions registered with DBOS must have unique names."
|
|
176
|
+
)
|
|
175
177
|
self.function_type_map[name] = functype
|
|
176
178
|
self.workflow_info_map[name] = wrapped_func
|
|
177
179
|
|
|
178
180
|
def register_class(self, cls: type, ci: DBOSClassInfo) -> None:
|
|
179
|
-
class_name = cls
|
|
181
|
+
class_name = _class_fqn(cls)
|
|
180
182
|
if class_name in self.class_info_map:
|
|
181
183
|
if self.class_info_map[class_name] is not cls:
|
|
182
184
|
raise Exception(f"Duplicate type registration for class '{class_name}'")
|
|
183
185
|
else:
|
|
184
186
|
self.class_info_map[class_name] = cls
|
|
185
187
|
|
|
186
|
-
def create_class_info(
|
|
187
|
-
|
|
188
|
+
def create_class_info(
|
|
189
|
+
self, cls: Type[T], class_name: Optional[str] = None
|
|
190
|
+
) -> Type[T]:
|
|
191
|
+
ci = get_or_create_class_info(cls, class_name)
|
|
188
192
|
self.register_class(cls, ci)
|
|
189
193
|
return cls
|
|
190
194
|
|
|
@@ -199,7 +203,7 @@ class DBOSRegistry:
|
|
|
199
203
|
|
|
200
204
|
def register_instance(self, inst: object) -> None:
|
|
201
205
|
config_name = getattr(inst, "config_name")
|
|
202
|
-
class_name = inst.__class__
|
|
206
|
+
class_name = _class_fqn(inst.__class__)
|
|
203
207
|
fn = f"{class_name}/{config_name}"
|
|
204
208
|
if fn in self.instance_info_map:
|
|
205
209
|
if self.instance_info_map[fn] is not inst:
|
|
@@ -209,15 +213,6 @@ class DBOSRegistry:
|
|
|
209
213
|
else:
|
|
210
214
|
self.instance_info_map[fn] = inst
|
|
211
215
|
|
|
212
|
-
def cancel_workflow(self, workflow_id: str) -> None:
|
|
213
|
-
self.workflow_cancelled_map[workflow_id] = True
|
|
214
|
-
|
|
215
|
-
def is_workflow_cancelled(self, workflow_id: str) -> bool:
|
|
216
|
-
return self.workflow_cancelled_map.get(workflow_id, False)
|
|
217
|
-
|
|
218
|
-
def clear_workflow_cancelled(self, workflow_id: str) -> None:
|
|
219
|
-
self.workflow_cancelled_map.pop(workflow_id, None)
|
|
220
|
-
|
|
221
216
|
def compute_app_version(self) -> str:
|
|
222
217
|
"""
|
|
223
218
|
An application's version is computed from a hash of the source of its workflows.
|
|
@@ -234,6 +229,13 @@ class DBOSRegistry:
|
|
|
234
229
|
hasher.update(source.encode("utf-8"))
|
|
235
230
|
return hasher.hexdigest()
|
|
236
231
|
|
|
232
|
+
def get_internal_queue(self) -> Queue:
|
|
233
|
+
"""
|
|
234
|
+
Get or create the internal queue used for the DBOS scheduler, for Kafka, and for
|
|
235
|
+
programmatic resuming and restarting of workflows.
|
|
236
|
+
"""
|
|
237
|
+
return Queue(INTERNAL_QUEUE_NAME)
|
|
238
|
+
|
|
237
239
|
|
|
238
240
|
class DBOS:
|
|
239
241
|
"""
|
|
@@ -335,6 +337,7 @@ class DBOS:
|
|
|
335
337
|
self.conductor_url: Optional[str] = conductor_url
|
|
336
338
|
self.conductor_key: Optional[str] = conductor_key
|
|
337
339
|
self.conductor_websocket: Optional[ConductorWebsocket] = None
|
|
340
|
+
self._background_event_loop: BackgroundEventLoop = BackgroundEventLoop()
|
|
338
341
|
|
|
339
342
|
init_logger()
|
|
340
343
|
|
|
@@ -344,6 +347,9 @@ class DBOS:
|
|
|
344
347
|
# If no config is provided, load it from dbos-config.yaml
|
|
345
348
|
unvalidated_config = load_config(run_process_config=False)
|
|
346
349
|
elif is_dbos_configfile(config):
|
|
350
|
+
dbos_logger.warning(
|
|
351
|
+
"ConfigFile config strutcture detected. This will be deprecated in favor of DBOSConfig in an upcoming release."
|
|
352
|
+
)
|
|
347
353
|
unvalidated_config = cast(ConfigFile, config)
|
|
348
354
|
if os.environ.get("DBOS__CLOUD") == "true":
|
|
349
355
|
unvalidated_config = overwrite_config(unvalidated_config)
|
|
@@ -357,13 +363,13 @@ class DBOS:
|
|
|
357
363
|
check_config_consistency(name=unvalidated_config["name"])
|
|
358
364
|
|
|
359
365
|
if unvalidated_config is not None:
|
|
360
|
-
self.
|
|
366
|
+
self._config: ConfigFile = process_config(data=unvalidated_config)
|
|
361
367
|
else:
|
|
362
368
|
raise ValueError("No valid configuration was loaded.")
|
|
363
369
|
|
|
364
|
-
set_env_vars(self.
|
|
365
|
-
config_logger(self.
|
|
366
|
-
dbos_tracer.config(self.
|
|
370
|
+
set_env_vars(self._config)
|
|
371
|
+
config_logger(self._config)
|
|
372
|
+
dbos_tracer.config(self._config)
|
|
367
373
|
dbos_logger.info("Initializing DBOS")
|
|
368
374
|
|
|
369
375
|
# If using FastAPI, set up middleware and lifecycle events
|
|
@@ -445,20 +451,21 @@ class DBOS:
|
|
|
445
451
|
dbos_logger.info(f"Executor ID: {GlobalParams.executor_id}")
|
|
446
452
|
dbos_logger.info(f"Application version: {GlobalParams.app_version}")
|
|
447
453
|
self._executor_field = ThreadPoolExecutor(max_workers=64)
|
|
454
|
+
self._background_event_loop.start()
|
|
448
455
|
self._sys_db_field = SystemDatabase(
|
|
449
|
-
self.
|
|
456
|
+
self._config["database"], debug_mode=debug_mode
|
|
450
457
|
)
|
|
451
458
|
self._app_db_field = ApplicationDatabase(
|
|
452
|
-
self.
|
|
459
|
+
self._config["database"], debug_mode=debug_mode
|
|
453
460
|
)
|
|
454
461
|
|
|
455
462
|
if debug_mode:
|
|
456
463
|
return
|
|
457
464
|
|
|
458
|
-
admin_port = self.
|
|
465
|
+
admin_port = self._config.get("runtimeConfig", {}).get("admin_port")
|
|
459
466
|
if admin_port is None:
|
|
460
467
|
admin_port = 3001
|
|
461
|
-
run_admin_server = self.
|
|
468
|
+
run_admin_server = self._config.get("runtimeConfig", {}).get(
|
|
462
469
|
"run_admin_server"
|
|
463
470
|
)
|
|
464
471
|
if run_admin_server:
|
|
@@ -489,6 +496,9 @@ class DBOS:
|
|
|
489
496
|
notification_listener_thread.start()
|
|
490
497
|
self._background_threads.append(notification_listener_thread)
|
|
491
498
|
|
|
499
|
+
# Create the internal queue if it has not yet been created
|
|
500
|
+
self._registry.get_internal_queue()
|
|
501
|
+
|
|
492
502
|
# Start the queue thread
|
|
493
503
|
evt = threading.Event()
|
|
494
504
|
self.stop_events.append(evt)
|
|
@@ -553,12 +563,13 @@ class DBOS:
|
|
|
553
563
|
assert (
|
|
554
564
|
not self._launched
|
|
555
565
|
), "The system database cannot be reset after DBOS is launched. Resetting the system database is a destructive operation that should only be used in a test environment."
|
|
556
|
-
reset_system_database(self.
|
|
566
|
+
reset_system_database(self._config)
|
|
557
567
|
|
|
558
568
|
def _destroy(self) -> None:
|
|
559
569
|
self._initialized = False
|
|
560
570
|
for event in self.stop_events:
|
|
561
571
|
event.set()
|
|
572
|
+
self._background_event_loop.stop()
|
|
562
573
|
if self._sys_db_field is not None:
|
|
563
574
|
self._sys_db_field.destroy()
|
|
564
575
|
self._sys_db_field = None
|
|
@@ -588,7 +599,7 @@ class DBOS:
|
|
|
588
599
|
# Decorators for DBOS functionality
|
|
589
600
|
@classmethod
|
|
590
601
|
def workflow(
|
|
591
|
-
cls, *, max_recovery_attempts: int = DEFAULT_MAX_RECOVERY_ATTEMPTS
|
|
602
|
+
cls, *, max_recovery_attempts: Optional[int] = DEFAULT_MAX_RECOVERY_ATTEMPTS
|
|
592
603
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
|
593
604
|
"""Decorate a function for use as a DBOS workflow."""
|
|
594
605
|
return decorate_workflow(_get_or_create_dbos_registry(), max_recovery_attempts)
|
|
@@ -635,15 +646,22 @@ class DBOS:
|
|
|
635
646
|
)
|
|
636
647
|
|
|
637
648
|
@classmethod
|
|
638
|
-
def dbos_class(
|
|
649
|
+
def dbos_class(
|
|
650
|
+
cls, class_name: Optional[str] = None
|
|
651
|
+
) -> Callable[[Type[T]], Type[T]]:
|
|
639
652
|
"""
|
|
640
653
|
Decorate a class that contains DBOS member functions.
|
|
641
654
|
|
|
642
655
|
All DBOS classes must be decorated, as this associates the class with
|
|
643
|
-
its member functions.
|
|
656
|
+
its member functions. Class names must be globally unique. By default, the class name is class.__qualname__ but you can optionally provide a class name that is different from the default name.
|
|
644
657
|
"""
|
|
645
658
|
|
|
646
|
-
|
|
659
|
+
def register_class(cls: Type[T]) -> Type[T]:
|
|
660
|
+
# Register the class with the DBOS registry
|
|
661
|
+
_get_or_create_dbos_registry().create_class_info(cls, class_name)
|
|
662
|
+
return cls
|
|
663
|
+
|
|
664
|
+
return register_class
|
|
647
665
|
|
|
648
666
|
@classmethod
|
|
649
667
|
def default_required_roles(cls, roles: List[str]) -> Callable[[Type[T]], Type[T]]:
|
|
@@ -724,32 +742,11 @@ class DBOS:
|
|
|
724
742
|
@classmethod
|
|
725
743
|
def get_workflow_status(cls, workflow_id: str) -> Optional[WorkflowStatus]:
|
|
726
744
|
"""Return the status of a workflow execution."""
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
if res is not None:
|
|
733
|
-
if res["output"]:
|
|
734
|
-
resstat: WorkflowStatus = _serialization.deserialize(res["output"])
|
|
735
|
-
return resstat
|
|
736
|
-
else:
|
|
737
|
-
raise DBOSException(
|
|
738
|
-
"Workflow status record not found. This should not happen! \033[1m Hint: Check if your workflow is deterministic.\033[0m"
|
|
739
|
-
)
|
|
740
|
-
stat = get_workflow(_get_dbos_instance()._sys_db, workflow_id, True)
|
|
741
|
-
|
|
742
|
-
if ctx and ctx.is_within_workflow():
|
|
743
|
-
sys_db.record_operation_result(
|
|
744
|
-
{
|
|
745
|
-
"workflow_uuid": ctx.workflow_id,
|
|
746
|
-
"function_id": ctx.function_id,
|
|
747
|
-
"function_name": "DBOS.getStatus",
|
|
748
|
-
"output": _serialization.serialize(stat),
|
|
749
|
-
"error": None,
|
|
750
|
-
}
|
|
751
|
-
)
|
|
752
|
-
return stat
|
|
745
|
+
|
|
746
|
+
def fn() -> Optional[WorkflowStatus]:
|
|
747
|
+
return get_workflow(_get_dbos_instance()._sys_db, workflow_id, True)
|
|
748
|
+
|
|
749
|
+
return _get_dbos_instance()._sys_db.call_function_as_step(fn, "DBOS.getStatus")
|
|
753
750
|
|
|
754
751
|
@classmethod
|
|
755
752
|
async def get_workflow_status_async(
|
|
@@ -925,17 +922,12 @@ class DBOS:
|
|
|
925
922
|
)
|
|
926
923
|
|
|
927
924
|
@classmethod
|
|
928
|
-
def
|
|
925
|
+
def _execute_workflow_id(cls, workflow_id: str) -> WorkflowHandle[Any]:
|
|
929
926
|
"""Execute a workflow by ID (for recovery)."""
|
|
930
927
|
return execute_workflow_by_id(_get_dbos_instance(), workflow_id)
|
|
931
928
|
|
|
932
929
|
@classmethod
|
|
933
|
-
def
|
|
934
|
-
"""Execute a workflow by ID (for recovery)."""
|
|
935
|
-
execute_workflow_by_id(_get_dbos_instance(), workflow_id, True)
|
|
936
|
-
|
|
937
|
-
@classmethod
|
|
938
|
-
def recover_pending_workflows(
|
|
930
|
+
def _recover_pending_workflows(
|
|
939
931
|
cls, executor_ids: List[str] = ["local"]
|
|
940
932
|
) -> List[WorkflowHandle[Any]]:
|
|
941
933
|
"""Find all PENDING workflows and execute them."""
|
|
@@ -944,17 +936,48 @@ class DBOS:
|
|
|
944
936
|
@classmethod
|
|
945
937
|
def cancel_workflow(cls, workflow_id: str) -> None:
|
|
946
938
|
"""Cancel a workflow by ID."""
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
939
|
+
|
|
940
|
+
def fn() -> None:
|
|
941
|
+
dbos_logger.info(f"Cancelling workflow: {workflow_id}")
|
|
942
|
+
_get_dbos_instance()._sys_db.cancel_workflow(workflow_id)
|
|
943
|
+
|
|
944
|
+
return _get_dbos_instance()._sys_db.call_function_as_step(
|
|
945
|
+
fn, "DBOS.cancelWorkflow"
|
|
946
|
+
)
|
|
950
947
|
|
|
951
948
|
@classmethod
|
|
952
949
|
def resume_workflow(cls, workflow_id: str) -> WorkflowHandle[Any]:
|
|
953
950
|
"""Resume a workflow by ID."""
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
951
|
+
|
|
952
|
+
def fn() -> None:
|
|
953
|
+
dbos_logger.info(f"Resuming workflow: {workflow_id}")
|
|
954
|
+
_get_dbos_instance()._sys_db.resume_workflow(workflow_id)
|
|
955
|
+
|
|
956
|
+
_get_dbos_instance()._sys_db.call_function_as_step(fn, "DBOS.resumeWorkflow")
|
|
957
|
+
return cls.retrieve_workflow(workflow_id)
|
|
958
|
+
|
|
959
|
+
@classmethod
|
|
960
|
+
def restart_workflow(cls, workflow_id: str) -> WorkflowHandle[Any]:
|
|
961
|
+
"""Restart a workflow with a new workflow ID"""
|
|
962
|
+
return cls.fork_workflow(workflow_id, 1)
|
|
963
|
+
|
|
964
|
+
@classmethod
|
|
965
|
+
def fork_workflow(cls, workflow_id: str, start_step: int) -> WorkflowHandle[Any]:
|
|
966
|
+
"""Restart a workflow with a new workflow ID from a specific step"""
|
|
967
|
+
|
|
968
|
+
def fn() -> str:
|
|
969
|
+
dbos_logger.info(f"Forking workflow: {workflow_id} from step {start_step}")
|
|
970
|
+
return fork_workflow(
|
|
971
|
+
_get_dbos_instance()._sys_db,
|
|
972
|
+
_get_dbos_instance()._app_db,
|
|
973
|
+
workflow_id,
|
|
974
|
+
start_step,
|
|
975
|
+
)
|
|
976
|
+
|
|
977
|
+
new_id = _get_dbos_instance()._sys_db.call_function_as_step(
|
|
978
|
+
fn, "DBOS.forkWorkflow"
|
|
979
|
+
)
|
|
980
|
+
return cls.retrieve_workflow(new_id)
|
|
958
981
|
|
|
959
982
|
@classmethod
|
|
960
983
|
def list_workflows(
|
|
@@ -970,19 +993,26 @@ class DBOS:
|
|
|
970
993
|
limit: Optional[int] = None,
|
|
971
994
|
offset: Optional[int] = None,
|
|
972
995
|
sort_desc: bool = False,
|
|
996
|
+
workflow_id_prefix: Optional[str] = None,
|
|
973
997
|
) -> List[WorkflowStatus]:
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
998
|
+
def fn() -> List[WorkflowStatus]:
|
|
999
|
+
return list_workflows(
|
|
1000
|
+
_get_dbos_instance()._sys_db,
|
|
1001
|
+
workflow_ids=workflow_ids,
|
|
1002
|
+
status=status,
|
|
1003
|
+
start_time=start_time,
|
|
1004
|
+
end_time=end_time,
|
|
1005
|
+
name=name,
|
|
1006
|
+
app_version=app_version,
|
|
1007
|
+
user=user,
|
|
1008
|
+
limit=limit,
|
|
1009
|
+
offset=offset,
|
|
1010
|
+
sort_desc=sort_desc,
|
|
1011
|
+
workflow_id_prefix=workflow_id_prefix,
|
|
1012
|
+
)
|
|
1013
|
+
|
|
1014
|
+
return _get_dbos_instance()._sys_db.call_function_as_step(
|
|
1015
|
+
fn, "DBOS.listWorkflows"
|
|
986
1016
|
)
|
|
987
1017
|
|
|
988
1018
|
@classmethod
|
|
@@ -998,16 +1028,32 @@ class DBOS:
|
|
|
998
1028
|
offset: Optional[int] = None,
|
|
999
1029
|
sort_desc: bool = False,
|
|
1000
1030
|
) -> List[WorkflowStatus]:
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1031
|
+
def fn() -> List[WorkflowStatus]:
|
|
1032
|
+
return list_queued_workflows(
|
|
1033
|
+
_get_dbos_instance()._sys_db,
|
|
1034
|
+
queue_name=queue_name,
|
|
1035
|
+
status=status,
|
|
1036
|
+
start_time=start_time,
|
|
1037
|
+
end_time=end_time,
|
|
1038
|
+
name=name,
|
|
1039
|
+
limit=limit,
|
|
1040
|
+
offset=offset,
|
|
1041
|
+
sort_desc=sort_desc,
|
|
1042
|
+
)
|
|
1043
|
+
|
|
1044
|
+
return _get_dbos_instance()._sys_db.call_function_as_step(
|
|
1045
|
+
fn, "DBOS.listQueuedWorkflows"
|
|
1046
|
+
)
|
|
1047
|
+
|
|
1048
|
+
@classmethod
|
|
1049
|
+
def list_workflow_steps(cls, workflow_id: str) -> List[StepInfo]:
|
|
1050
|
+
def fn() -> List[StepInfo]:
|
|
1051
|
+
return list_workflow_steps(
|
|
1052
|
+
_get_dbos_instance()._sys_db, _get_dbos_instance()._app_db, workflow_id
|
|
1053
|
+
)
|
|
1054
|
+
|
|
1055
|
+
return _get_dbos_instance()._sys_db.call_function_as_step(
|
|
1056
|
+
fn, "DBOS.listWorkflowSteps"
|
|
1011
1057
|
)
|
|
1012
1058
|
|
|
1013
1059
|
@classproperty
|
|
@@ -1020,15 +1066,15 @@ class DBOS:
|
|
|
1020
1066
|
"""Return the DBOS `ConfigFile` for the current context."""
|
|
1021
1067
|
global _dbos_global_instance
|
|
1022
1068
|
if _dbos_global_instance is not None:
|
|
1023
|
-
return _dbos_global_instance.
|
|
1069
|
+
return _dbos_global_instance._config
|
|
1024
1070
|
reg = _get_or_create_dbos_registry()
|
|
1025
1071
|
if reg.config is not None:
|
|
1026
1072
|
return reg.config
|
|
1027
|
-
|
|
1073
|
+
loaded_config = (
|
|
1028
1074
|
load_config()
|
|
1029
1075
|
) # This will return the processed & validated config (with defaults)
|
|
1030
|
-
reg.config =
|
|
1031
|
-
return
|
|
1076
|
+
reg.config = loaded_config
|
|
1077
|
+
return loaded_config
|
|
1032
1078
|
|
|
1033
1079
|
@classproperty
|
|
1034
1080
|
def sql_session(cls) -> Session:
|
|
@@ -1050,11 +1096,11 @@ class DBOS:
|
|
|
1050
1096
|
|
|
1051
1097
|
@classproperty
|
|
1052
1098
|
def step_id(cls) -> int:
|
|
1053
|
-
"""Return the step ID for the
|
|
1099
|
+
"""Return the step ID for the currently executing step. This is a unique identifier of the current step within the workflow."""
|
|
1054
1100
|
ctx = assert_current_dbos_context()
|
|
1055
1101
|
assert (
|
|
1056
|
-
ctx.
|
|
1057
|
-
), "step_id is only available within a DBOS
|
|
1102
|
+
ctx.is_step() or ctx.is_transaction()
|
|
1103
|
+
), "step_id is only available within a DBOS step."
|
|
1058
1104
|
return ctx.function_id
|
|
1059
1105
|
|
|
1060
1106
|
@classproperty
|
|
@@ -1083,7 +1129,9 @@ class DBOS:
|
|
|
1083
1129
|
def span(cls) -> Span:
|
|
1084
1130
|
"""Return the tracing `Span` associated with the current context."""
|
|
1085
1131
|
ctx = assert_current_dbos_context()
|
|
1086
|
-
|
|
1132
|
+
span = ctx.get_current_span()
|
|
1133
|
+
assert span
|
|
1134
|
+
return span
|
|
1087
1135
|
|
|
1088
1136
|
@classproperty
|
|
1089
1137
|
def request(cls) -> Optional["Request"]:
|