dbos 0.11.0a4__py3-none-any.whl → 0.13.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/__init__.py +7 -7
- dbos/{admin_sever.py → _admin_sever.py} +15 -21
- dbos/{application_database.py → _app_db.py} +4 -5
- dbos/{decorators.py → _classproperty.py} +3 -3
- dbos/{context.py → _context.py} +26 -26
- dbos/{core.py → _core.py} +121 -107
- dbos/{dbos.py → _dbos.py} +57 -59
- dbos/{dbos_config.py → _dbos_config.py} +9 -9
- dbos/{fastapi.py → _fastapi.py} +10 -11
- dbos/{flask.py → _flask.py} +6 -7
- dbos/{kafka.py → _kafka.py} +18 -18
- dbos/{logger.py → _logger.py} +13 -13
- dbos/{queue.py → _queue.py} +7 -7
- dbos/{recovery.py → _recovery.py} +8 -8
- dbos/{roles.py → _roles.py} +5 -5
- dbos/{scheduler/scheduler.py → _scheduler.py} +17 -7
- dbos/{utils.py → _serialization.py} +4 -4
- dbos/{system_database.py → _sys_db.py} +42 -37
- dbos/{tracer.py → _tracer.py} +2 -2
- dbos/cli.py +21 -21
- {dbos-0.11.0a4.dist-info → dbos-0.13.0.dist-info}/METADATA +1 -2
- dbos-0.13.0.dist-info/RECORD +54 -0
- {dbos-0.11.0a4.dist-info → dbos-0.13.0.dist-info}/WHEEL +1 -1
- dbos-0.11.0a4.dist-info/RECORD +0 -54
- /dbos/{scheduler/croniter.py → _croniter.py} +0 -0
- /dbos/{error.py → _error.py} +0 -0
- /dbos/{kafka_message.py → _kafka_message.py} +0 -0
- /dbos/{migrations → _migrations}/env.py +0 -0
- /dbos/{migrations → _migrations}/script.py.mako +0 -0
- /dbos/{migrations → _migrations}/versions/50f3227f0b4b_fix_job_queue.py +0 -0
- /dbos/{migrations → _migrations}/versions/5c361fc04708_added_system_tables.py +0 -0
- /dbos/{migrations → _migrations}/versions/a3b18ad34abe_added_triggers.py +0 -0
- /dbos/{migrations → _migrations}/versions/d76646551a6b_job_queue_limiter.py +0 -0
- /dbos/{migrations → _migrations}/versions/d76646551a6c_workflow_queue.py +0 -0
- /dbos/{migrations → _migrations}/versions/eab0cc1d9a14_job_queue.py +0 -0
- /dbos/{registrations.py → _registrations.py} +0 -0
- /dbos/{request.py → _request.py} +0 -0
- /dbos/{schemas → _schemas}/__init__.py +0 -0
- /dbos/{schemas → _schemas}/application_database.py +0 -0
- /dbos/{schemas → _schemas}/system_database.py +0 -0
- /dbos/{templates → _templates}/hello/README.md +0 -0
- /dbos/{templates → _templates}/hello/__package/__init__.py +0 -0
- /dbos/{templates → _templates}/hello/__package/main.py +0 -0
- /dbos/{templates → _templates}/hello/__package/schema.py +0 -0
- /dbos/{templates → _templates}/hello/alembic.ini +0 -0
- /dbos/{templates → _templates}/hello/dbos-config.yaml.dbos +0 -0
- /dbos/{templates → _templates}/hello/migrations/env.py.dbos +0 -0
- /dbos/{templates → _templates}/hello/migrations/script.py.mako +0 -0
- /dbos/{templates → _templates}/hello/migrations/versions/2024_07_31_180642_init.py +0 -0
- /dbos/{templates → _templates}/hello/start_postgres_docker.py +0 -0
- {dbos-0.11.0a4.dist-info → dbos-0.13.0.dist-info}/entry_points.txt +0 -0
- {dbos-0.11.0a4.dist-info → dbos-0.13.0.dist-info}/licenses/LICENSE +0 -0
dbos/{core.py → _core.py}
RENAMED
|
@@ -6,15 +6,15 @@ from concurrent.futures import Future
|
|
|
6
6
|
from functools import wraps
|
|
7
7
|
from typing import TYPE_CHECKING, Any, Callable, Generic, Optional, Tuple, TypeVar, cast
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from ._app_db import ApplicationDatabase, TransactionResultInternal
|
|
10
10
|
|
|
11
11
|
if sys.version_info < (3, 10):
|
|
12
12
|
from typing_extensions import ParamSpec
|
|
13
13
|
else:
|
|
14
14
|
from typing import ParamSpec
|
|
15
15
|
|
|
16
|
-
from
|
|
17
|
-
from
|
|
16
|
+
from . import _serialization
|
|
17
|
+
from ._context import (
|
|
18
18
|
DBOSAssumeRole,
|
|
19
19
|
DBOSContext,
|
|
20
20
|
DBOSContextEnsure,
|
|
@@ -29,7 +29,7 @@ from dbos.context import (
|
|
|
29
29
|
assert_current_dbos_context,
|
|
30
30
|
get_local_dbos_context,
|
|
31
31
|
)
|
|
32
|
-
from
|
|
32
|
+
from ._error import (
|
|
33
33
|
DBOSException,
|
|
34
34
|
DBOSMaxStepRetriesExceeded,
|
|
35
35
|
DBOSNonExistentWorkflowError,
|
|
@@ -37,7 +37,7 @@ from dbos.error import (
|
|
|
37
37
|
DBOSWorkflowConflictIDError,
|
|
38
38
|
DBOSWorkflowFunctionNotFoundError,
|
|
39
39
|
)
|
|
40
|
-
from
|
|
40
|
+
from ._registrations import (
|
|
41
41
|
DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
|
42
42
|
get_config_name,
|
|
43
43
|
get_dbos_class_name,
|
|
@@ -48,18 +48,24 @@ from dbos.registrations import (
|
|
|
48
48
|
set_dbos_func_name,
|
|
49
49
|
set_temp_workflow_type,
|
|
50
50
|
)
|
|
51
|
-
from
|
|
52
|
-
from
|
|
51
|
+
from ._roles import check_required_roles
|
|
52
|
+
from ._serialization import WorkflowInputs
|
|
53
|
+
from ._sys_db import (
|
|
53
54
|
GetEventWorkflowContext,
|
|
54
55
|
OperationResultInternal,
|
|
55
56
|
WorkflowStatusInternal,
|
|
56
57
|
WorkflowStatusString,
|
|
57
58
|
)
|
|
58
|
-
from dbos.utils import WorkflowInputs
|
|
59
59
|
|
|
60
60
|
if TYPE_CHECKING:
|
|
61
|
-
from
|
|
62
|
-
|
|
61
|
+
from ._dbos import (
|
|
62
|
+
DBOS,
|
|
63
|
+
Workflow,
|
|
64
|
+
WorkflowHandle,
|
|
65
|
+
WorkflowStatus,
|
|
66
|
+
DBOSRegistry,
|
|
67
|
+
IsolationLevel,
|
|
68
|
+
)
|
|
63
69
|
|
|
64
70
|
from sqlalchemy.exc import DBAPIError
|
|
65
71
|
|
|
@@ -70,7 +76,7 @@ F = TypeVar("F", bound=Callable[..., Any])
|
|
|
70
76
|
TEMP_SEND_WF_NAME = "<temp>.temp_send_workflow"
|
|
71
77
|
|
|
72
78
|
|
|
73
|
-
class
|
|
79
|
+
class WorkflowHandleFuture(Generic[R]):
|
|
74
80
|
|
|
75
81
|
def __init__(self, workflow_id: str, future: Future[R], dbos: "DBOS"):
|
|
76
82
|
self.workflow_id = workflow_id
|
|
@@ -90,7 +96,7 @@ class _WorkflowHandleFuture(Generic[R]):
|
|
|
90
96
|
return stat
|
|
91
97
|
|
|
92
98
|
|
|
93
|
-
class
|
|
99
|
+
class WorkflowHandlePolling(Generic[R]):
|
|
94
100
|
|
|
95
101
|
def __init__(self, workflow_id: str, dbos: "DBOS"):
|
|
96
102
|
self.workflow_id = workflow_id
|
|
@@ -141,7 +147,9 @@ def _init_workflow(
|
|
|
141
147
|
"app_id": ctx.app_id,
|
|
142
148
|
"app_version": ctx.app_version,
|
|
143
149
|
"executor_id": ctx.executor_id,
|
|
144
|
-
"request": (
|
|
150
|
+
"request": (
|
|
151
|
+
_serialization.serialize(ctx.request) if ctx.request is not None else None
|
|
152
|
+
),
|
|
145
153
|
"recovery_attempts": None,
|
|
146
154
|
"authenticated_user": ctx.authenticated_user,
|
|
147
155
|
"authenticated_roles": (
|
|
@@ -162,10 +170,10 @@ def _init_workflow(
|
|
|
162
170
|
dbos._sys_db.update_workflow_status(
|
|
163
171
|
status, False, ctx.in_recovery, max_recovery_attempts=max_recovery_attempts
|
|
164
172
|
)
|
|
165
|
-
dbos._sys_db.update_workflow_inputs(wfid,
|
|
173
|
+
dbos._sys_db.update_workflow_inputs(wfid, _serialization.serialize_args(inputs))
|
|
166
174
|
else:
|
|
167
175
|
# Buffer the inputs for single-transaction workflows, but don't buffer the status
|
|
168
|
-
dbos._sys_db.buffer_workflow_inputs(wfid,
|
|
176
|
+
dbos._sys_db.buffer_workflow_inputs(wfid, _serialization.serialize_args(inputs))
|
|
169
177
|
|
|
170
178
|
if queue is not None:
|
|
171
179
|
dbos._sys_db.enqueue(wfid, queue)
|
|
@@ -183,7 +191,7 @@ def _execute_workflow(
|
|
|
183
191
|
try:
|
|
184
192
|
output = func(*args, **kwargs)
|
|
185
193
|
status["status"] = "SUCCESS"
|
|
186
|
-
status["output"] =
|
|
194
|
+
status["output"] = _serialization.serialize(output)
|
|
187
195
|
if status["queue_name"] is not None:
|
|
188
196
|
queue = dbos._registry.queue_info_map[status["queue_name"]]
|
|
189
197
|
dbos._sys_db.remove_from_queue(status["workflow_uuid"], queue)
|
|
@@ -198,7 +206,7 @@ def _execute_workflow(
|
|
|
198
206
|
return output
|
|
199
207
|
except Exception as error:
|
|
200
208
|
status["status"] = "ERROR"
|
|
201
|
-
status["error"] =
|
|
209
|
+
status["error"] = _serialization.serialize_exception(error)
|
|
202
210
|
if status["queue_name"] is not None:
|
|
203
211
|
queue = dbos._registry.queue_info_map[status["queue_name"]]
|
|
204
212
|
dbos._sys_db.remove_from_queue(status["workflow_uuid"], queue)
|
|
@@ -231,7 +239,7 @@ def _execute_workflow_wthread(
|
|
|
231
239
|
raise
|
|
232
240
|
|
|
233
241
|
|
|
234
|
-
def
|
|
242
|
+
def execute_workflow_by_id(dbos: "DBOS", workflow_id: str) -> "WorkflowHandle[Any]":
|
|
235
243
|
status = dbos._sys_db.get_workflow_status(workflow_id)
|
|
236
244
|
if not status:
|
|
237
245
|
raise DBOSRecoveryError(workflow_id, "Workflow status not found")
|
|
@@ -246,7 +254,9 @@ def _execute_workflow_id(dbos: "DBOS", workflow_id: str) -> "WorkflowHandle[Any]
|
|
|
246
254
|
with DBOSContextEnsure():
|
|
247
255
|
ctx = assert_current_dbos_context()
|
|
248
256
|
request = status["request"]
|
|
249
|
-
ctx.request =
|
|
257
|
+
ctx.request = (
|
|
258
|
+
_serialization.deserialize(request) if request is not None else None
|
|
259
|
+
)
|
|
250
260
|
if status["config_name"] is not None:
|
|
251
261
|
config_name = status["config_name"]
|
|
252
262
|
class_name = status["class_name"]
|
|
@@ -257,7 +267,7 @@ def _execute_workflow_id(dbos: "DBOS", workflow_id: str) -> "WorkflowHandle[Any]
|
|
|
257
267
|
f"Cannot execute workflow because instance '{iname}' is not registered",
|
|
258
268
|
)
|
|
259
269
|
with SetWorkflowID(workflow_id):
|
|
260
|
-
return
|
|
270
|
+
return start_workflow(
|
|
261
271
|
dbos,
|
|
262
272
|
wf_func,
|
|
263
273
|
status["queue_name"],
|
|
@@ -274,7 +284,7 @@ def _execute_workflow_id(dbos: "DBOS", workflow_id: str) -> "WorkflowHandle[Any]
|
|
|
274
284
|
f"Cannot execute workflow because class '{class_name}' is not registered",
|
|
275
285
|
)
|
|
276
286
|
with SetWorkflowID(workflow_id):
|
|
277
|
-
return
|
|
287
|
+
return start_workflow(
|
|
278
288
|
dbos,
|
|
279
289
|
wf_func,
|
|
280
290
|
status["queue_name"],
|
|
@@ -285,7 +295,7 @@ def _execute_workflow_id(dbos: "DBOS", workflow_id: str) -> "WorkflowHandle[Any]
|
|
|
285
295
|
)
|
|
286
296
|
else:
|
|
287
297
|
with SetWorkflowID(workflow_id):
|
|
288
|
-
return
|
|
298
|
+
return start_workflow(
|
|
289
299
|
dbos,
|
|
290
300
|
wf_func,
|
|
291
301
|
status["queue_name"],
|
|
@@ -295,69 +305,7 @@ def _execute_workflow_id(dbos: "DBOS", workflow_id: str) -> "WorkflowHandle[Any]
|
|
|
295
305
|
)
|
|
296
306
|
|
|
297
307
|
|
|
298
|
-
def
|
|
299
|
-
dbosreg: "_DBOSRegistry",
|
|
300
|
-
func: F,
|
|
301
|
-
max_recovery_attempts: int = DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
|
302
|
-
) -> F:
|
|
303
|
-
func.__orig_func = func # type: ignore
|
|
304
|
-
|
|
305
|
-
fi = get_or_create_func_info(func)
|
|
306
|
-
fi.max_recovery_attempts = max_recovery_attempts
|
|
307
|
-
|
|
308
|
-
@wraps(func)
|
|
309
|
-
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
310
|
-
if dbosreg.dbos is None:
|
|
311
|
-
raise DBOSException(
|
|
312
|
-
f"Function {func.__name__} invoked before DBOS initialized"
|
|
313
|
-
)
|
|
314
|
-
dbos = dbosreg.dbos
|
|
315
|
-
|
|
316
|
-
rr: Optional[str] = check_required_roles(func, fi)
|
|
317
|
-
attributes: TracedAttributes = {
|
|
318
|
-
"name": func.__name__,
|
|
319
|
-
"operationType": OperationType.WORKFLOW.value,
|
|
320
|
-
}
|
|
321
|
-
inputs: WorkflowInputs = {
|
|
322
|
-
"args": args,
|
|
323
|
-
"kwargs": kwargs,
|
|
324
|
-
}
|
|
325
|
-
ctx = get_local_dbos_context()
|
|
326
|
-
enterWorkflowCtxMgr = (
|
|
327
|
-
EnterDBOSChildWorkflow if ctx and ctx.is_workflow() else EnterDBOSWorkflow
|
|
328
|
-
)
|
|
329
|
-
with enterWorkflowCtxMgr(attributes), DBOSAssumeRole(rr):
|
|
330
|
-
ctx = assert_current_dbos_context() # Now the child ctx
|
|
331
|
-
status = _init_workflow(
|
|
332
|
-
dbos,
|
|
333
|
-
ctx,
|
|
334
|
-
inputs=inputs,
|
|
335
|
-
wf_name=get_dbos_func_name(func),
|
|
336
|
-
class_name=get_dbos_class_name(fi, func, args),
|
|
337
|
-
config_name=get_config_name(fi, func, args),
|
|
338
|
-
temp_wf_type=get_temp_workflow_type(func),
|
|
339
|
-
max_recovery_attempts=max_recovery_attempts,
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
dbos.logger.debug(
|
|
343
|
-
f"Running workflow, id: {ctx.workflow_id}, name: {get_dbos_func_name(func)}"
|
|
344
|
-
)
|
|
345
|
-
return _execute_workflow(dbos, status, func, *args, **kwargs)
|
|
346
|
-
|
|
347
|
-
wrapped_func = cast(F, wrapper)
|
|
348
|
-
return wrapped_func
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
def _workflow(reg: "_DBOSRegistry", max_recovery_attempts: int) -> Callable[[F], F]:
|
|
352
|
-
def _workflow_decorator(func: F) -> F:
|
|
353
|
-
wrapped_func = _workflow_wrapper(reg, func, max_recovery_attempts)
|
|
354
|
-
reg.register_wf_function(func.__qualname__, wrapped_func)
|
|
355
|
-
return wrapped_func
|
|
356
|
-
|
|
357
|
-
return _workflow_decorator
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
def _start_workflow(
|
|
308
|
+
def start_workflow(
|
|
361
309
|
dbos: "DBOS",
|
|
362
310
|
func: "Workflow[P, R]",
|
|
363
311
|
queue_name: Optional[str],
|
|
@@ -420,7 +368,7 @@ def _start_workflow(
|
|
|
420
368
|
)
|
|
421
369
|
|
|
422
370
|
if not execute_workflow:
|
|
423
|
-
return
|
|
371
|
+
return WorkflowHandlePolling(new_wf_id, dbos)
|
|
424
372
|
|
|
425
373
|
if fself is not None:
|
|
426
374
|
future = dbos._executor.submit(
|
|
@@ -443,11 +391,75 @@ def _start_workflow(
|
|
|
443
391
|
*args,
|
|
444
392
|
**kwargs,
|
|
445
393
|
)
|
|
446
|
-
return
|
|
394
|
+
return WorkflowHandleFuture(new_wf_id, future, dbos)
|
|
447
395
|
|
|
448
396
|
|
|
449
|
-
def
|
|
450
|
-
dbosreg: "
|
|
397
|
+
def workflow_wrapper(
|
|
398
|
+
dbosreg: "DBOSRegistry",
|
|
399
|
+
func: F,
|
|
400
|
+
max_recovery_attempts: int = DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
|
401
|
+
) -> F:
|
|
402
|
+
func.__orig_func = func # type: ignore
|
|
403
|
+
|
|
404
|
+
fi = get_or_create_func_info(func)
|
|
405
|
+
fi.max_recovery_attempts = max_recovery_attempts
|
|
406
|
+
|
|
407
|
+
@wraps(func)
|
|
408
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
409
|
+
if dbosreg.dbos is None:
|
|
410
|
+
raise DBOSException(
|
|
411
|
+
f"Function {func.__name__} invoked before DBOS initialized"
|
|
412
|
+
)
|
|
413
|
+
dbos = dbosreg.dbos
|
|
414
|
+
|
|
415
|
+
rr: Optional[str] = check_required_roles(func, fi)
|
|
416
|
+
attributes: TracedAttributes = {
|
|
417
|
+
"name": func.__name__,
|
|
418
|
+
"operationType": OperationType.WORKFLOW.value,
|
|
419
|
+
}
|
|
420
|
+
inputs: WorkflowInputs = {
|
|
421
|
+
"args": args,
|
|
422
|
+
"kwargs": kwargs,
|
|
423
|
+
}
|
|
424
|
+
ctx = get_local_dbos_context()
|
|
425
|
+
enterWorkflowCtxMgr = (
|
|
426
|
+
EnterDBOSChildWorkflow if ctx and ctx.is_workflow() else EnterDBOSWorkflow
|
|
427
|
+
)
|
|
428
|
+
with enterWorkflowCtxMgr(attributes), DBOSAssumeRole(rr):
|
|
429
|
+
ctx = assert_current_dbos_context() # Now the child ctx
|
|
430
|
+
status = _init_workflow(
|
|
431
|
+
dbos,
|
|
432
|
+
ctx,
|
|
433
|
+
inputs=inputs,
|
|
434
|
+
wf_name=get_dbos_func_name(func),
|
|
435
|
+
class_name=get_dbos_class_name(fi, func, args),
|
|
436
|
+
config_name=get_config_name(fi, func, args),
|
|
437
|
+
temp_wf_type=get_temp_workflow_type(func),
|
|
438
|
+
max_recovery_attempts=max_recovery_attempts,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
dbos.logger.debug(
|
|
442
|
+
f"Running workflow, id: {ctx.workflow_id}, name: {get_dbos_func_name(func)}"
|
|
443
|
+
)
|
|
444
|
+
return _execute_workflow(dbos, status, func, *args, **kwargs)
|
|
445
|
+
|
|
446
|
+
wrapped_func = cast(F, wrapper)
|
|
447
|
+
return wrapped_func
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def decorate_workflow(
|
|
451
|
+
reg: "DBOSRegistry", max_recovery_attempts: int
|
|
452
|
+
) -> Callable[[F], F]:
|
|
453
|
+
def _workflow_decorator(func: F) -> F:
|
|
454
|
+
wrapped_func = workflow_wrapper(reg, func, max_recovery_attempts)
|
|
455
|
+
reg.register_wf_function(func.__qualname__, wrapped_func)
|
|
456
|
+
return wrapped_func
|
|
457
|
+
|
|
458
|
+
return _workflow_decorator
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def decorate_transaction(
|
|
462
|
+
dbosreg: "DBOSRegistry", isolation_level: "IsolationLevel" = "SERIALIZABLE"
|
|
451
463
|
) -> Callable[[F], F]:
|
|
452
464
|
def decorator(func: F) -> F:
|
|
453
465
|
def invoke_tx(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -498,14 +510,14 @@ def _transaction(
|
|
|
498
510
|
)
|
|
499
511
|
if recorded_output["error"]:
|
|
500
512
|
deserialized_error = (
|
|
501
|
-
|
|
513
|
+
_serialization.deserialize_exception(
|
|
502
514
|
recorded_output["error"]
|
|
503
515
|
)
|
|
504
516
|
)
|
|
505
517
|
has_recorded_error = True
|
|
506
518
|
raise deserialized_error
|
|
507
519
|
elif recorded_output["output"]:
|
|
508
|
-
return
|
|
520
|
+
return _serialization.deserialize(
|
|
509
521
|
recorded_output["output"]
|
|
510
522
|
)
|
|
511
523
|
else:
|
|
@@ -518,7 +530,7 @@ def _transaction(
|
|
|
518
530
|
)
|
|
519
531
|
|
|
520
532
|
output = func(*args, **kwargs)
|
|
521
|
-
txn_output["output"] =
|
|
533
|
+
txn_output["output"] = _serialization.serialize(output)
|
|
522
534
|
assert (
|
|
523
535
|
ctx.sql_session is not None
|
|
524
536
|
), "Cannot find a database connection"
|
|
@@ -543,7 +555,9 @@ def _transaction(
|
|
|
543
555
|
except Exception as error:
|
|
544
556
|
# Don't record the error if it was already recorded
|
|
545
557
|
if not has_recorded_error:
|
|
546
|
-
txn_output["error"] =
|
|
558
|
+
txn_output["error"] = (
|
|
559
|
+
_serialization.serialize_exception(error)
|
|
560
|
+
)
|
|
547
561
|
dbos._app_db.record_transaction_error(txn_output)
|
|
548
562
|
raise
|
|
549
563
|
return output
|
|
@@ -571,7 +585,7 @@ def _transaction(
|
|
|
571
585
|
def temp_wf(*args: Any, **kwargs: Any) -> Any:
|
|
572
586
|
return wrapper(*args, **kwargs)
|
|
573
587
|
|
|
574
|
-
wrapped_wf =
|
|
588
|
+
wrapped_wf = workflow_wrapper(dbosreg, temp_wf)
|
|
575
589
|
set_dbos_func_name(temp_wf, "<temp>." + func.__qualname__)
|
|
576
590
|
set_temp_workflow_type(temp_wf, "transaction")
|
|
577
591
|
dbosreg.register_wf_function(get_dbos_func_name(temp_wf), wrapped_wf)
|
|
@@ -582,8 +596,8 @@ def _transaction(
|
|
|
582
596
|
return decorator
|
|
583
597
|
|
|
584
598
|
|
|
585
|
-
def
|
|
586
|
-
dbosreg: "
|
|
599
|
+
def decorate_step(
|
|
600
|
+
dbosreg: "DBOSRegistry",
|
|
587
601
|
*,
|
|
588
602
|
retries_allowed: bool = False,
|
|
589
603
|
interval_seconds: float = 1.0,
|
|
@@ -618,12 +632,12 @@ def _step(
|
|
|
618
632
|
f"Replaying step, id: {ctx.function_id}, name: {attributes['name']}"
|
|
619
633
|
)
|
|
620
634
|
if recorded_output["error"] is not None:
|
|
621
|
-
deserialized_error =
|
|
635
|
+
deserialized_error = _serialization.deserialize_exception(
|
|
622
636
|
recorded_output["error"]
|
|
623
637
|
)
|
|
624
638
|
raise deserialized_error
|
|
625
639
|
elif recorded_output["output"] is not None:
|
|
626
|
-
return
|
|
640
|
+
return _serialization.deserialize(recorded_output["output"])
|
|
627
641
|
else:
|
|
628
642
|
raise Exception("Output and error are both None")
|
|
629
643
|
else:
|
|
@@ -639,7 +653,7 @@ def _step(
|
|
|
639
653
|
for attempt in range(1, local_max_attempts + 1):
|
|
640
654
|
try:
|
|
641
655
|
output = func(*args, **kwargs)
|
|
642
|
-
step_output["output"] =
|
|
656
|
+
step_output["output"] = _serialization.serialize(output)
|
|
643
657
|
error = None
|
|
644
658
|
break
|
|
645
659
|
except Exception as err:
|
|
@@ -665,7 +679,9 @@ def _step(
|
|
|
665
679
|
)
|
|
666
680
|
|
|
667
681
|
step_output["error"] = (
|
|
668
|
-
|
|
682
|
+
_serialization.serialize_exception(error)
|
|
683
|
+
if error is not None
|
|
684
|
+
else None
|
|
669
685
|
)
|
|
670
686
|
dbos._sys_db.record_operation_result(step_output)
|
|
671
687
|
|
|
@@ -698,7 +714,7 @@ def _step(
|
|
|
698
714
|
def temp_wf(*args: Any, **kwargs: Any) -> Any:
|
|
699
715
|
return wrapper(*args, **kwargs)
|
|
700
716
|
|
|
701
|
-
wrapped_wf =
|
|
717
|
+
wrapped_wf = workflow_wrapper(dbosreg, temp_wf)
|
|
702
718
|
set_dbos_func_name(temp_wf, "<temp>." + func.__qualname__)
|
|
703
719
|
set_temp_workflow_type(temp_wf, "step")
|
|
704
720
|
dbosreg.register_wf_function(get_dbos_func_name(temp_wf), wrapped_wf)
|
|
@@ -709,7 +725,7 @@ def _step(
|
|
|
709
725
|
return decorator
|
|
710
726
|
|
|
711
727
|
|
|
712
|
-
def
|
|
728
|
+
def send(
|
|
713
729
|
dbos: "DBOS", destination_id: str, message: Any, topic: Optional[str] = None
|
|
714
730
|
) -> None:
|
|
715
731
|
def do_send(destination_id: str, message: Any, topic: Optional[str]) -> None:
|
|
@@ -735,9 +751,7 @@ def _send(
|
|
|
735
751
|
wffn(destination_id, message, topic)
|
|
736
752
|
|
|
737
753
|
|
|
738
|
-
def
|
|
739
|
-
dbos: "DBOS", topic: Optional[str] = None, timeout_seconds: float = 60
|
|
740
|
-
) -> Any:
|
|
754
|
+
def recv(dbos: "DBOS", topic: Optional[str] = None, timeout_seconds: float = 60) -> Any:
|
|
741
755
|
cur_ctx = get_local_dbos_context()
|
|
742
756
|
if cur_ctx is not None:
|
|
743
757
|
# Must call it within a workflow
|
|
@@ -760,7 +774,7 @@ def _recv(
|
|
|
760
774
|
raise DBOSException("recv() must be called from within a workflow")
|
|
761
775
|
|
|
762
776
|
|
|
763
|
-
def
|
|
777
|
+
def set_event(dbos: "DBOS", key: str, value: Any) -> None:
|
|
764
778
|
cur_ctx = get_local_dbos_context()
|
|
765
779
|
if cur_ctx is not None:
|
|
766
780
|
# Must call it within a workflow
|
|
@@ -779,7 +793,7 @@ def _set_event(dbos: "DBOS", key: str, value: Any) -> None:
|
|
|
779
793
|
raise DBOSException("set_event() must be called from within a workflow")
|
|
780
794
|
|
|
781
795
|
|
|
782
|
-
def
|
|
796
|
+
def get_event(
|
|
783
797
|
dbos: "DBOS", workflow_id: str, key: str, timeout_seconds: float = 60
|
|
784
798
|
) -> Any:
|
|
785
799
|
cur_ctx = get_local_dbos_context()
|