dbos 0.16.0a2__tar.gz → 0.17.0__tar.gz
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-0.16.0a2 → dbos-0.17.0}/PKG-INFO +1 -1
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_core.py +3 -3
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_dbos.py +3 -2
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_outcome.py +23 -7
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_queue.py +2 -2
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_sys_db.py +6 -3
- {dbos-0.16.0a2 → dbos-0.17.0}/pyproject.toml +1 -1
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_dbos.py +127 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/LICENSE +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/README.md +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/__init__.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_admin_server.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_app_db.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_classproperty.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_context.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_croniter.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_dbos_config.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_error.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_fastapi.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_flask.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_kafka.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_kafka_message.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_logger.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/env.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/script.py.mako +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_recovery.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_registrations.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_request.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_roles.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_scheduler.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_schemas/__init__.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_schemas/application_database.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_schemas/system_database.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_serialization.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/README.md +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/__package/__init__.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/__package/main.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/__package/schema.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/alembic.ini +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/dbos-config.yaml.dbos +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/migrations/env.py.dbos +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/migrations/script.py.mako +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/migrations/versions/2024_07_31_180642_init.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/start_postgres_docker.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/_tracer.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/cli.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/dbos-config.schema.json +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/dbos/py.typed +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/__init__.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/atexit_no_ctor.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/atexit_no_launch.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/classdefs.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/conftest.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/more_classdefs.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_admin_server.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_async.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_classdecorators.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_concurrency.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_config.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_croniter.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_failures.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_fastapi.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_fastapi_roles.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_flask.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_kafka.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_outcome.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_package.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_queue.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_scheduler.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_schema_migration.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_singleton.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/tests/test_spans.py +0 -0
- {dbos-0.16.0a2 → dbos-0.17.0}/version/__init__.py +0 -0
|
@@ -21,7 +21,7 @@ from typing import (
|
|
|
21
21
|
overload,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
from dbos._outcome import Immediate, Outcome, Pending
|
|
24
|
+
from dbos._outcome import Immediate, NoResult, Outcome, Pending
|
|
25
25
|
|
|
26
26
|
from ._app_db import ApplicationDatabase, TransactionResultInternal
|
|
27
27
|
|
|
@@ -719,7 +719,7 @@ def decorate_step(
|
|
|
719
719
|
finally:
|
|
720
720
|
dbos._sys_db.record_operation_result(step_output)
|
|
721
721
|
|
|
722
|
-
def check_existing_result() ->
|
|
722
|
+
def check_existing_result() -> Union[NoResult, R]:
|
|
723
723
|
ctx = assert_current_dbos_context()
|
|
724
724
|
recorded_output = dbos._sys_db.check_operation_execution(
|
|
725
725
|
ctx.workflow_id, ctx.function_id
|
|
@@ -743,7 +743,7 @@ def decorate_step(
|
|
|
743
743
|
dbos.logger.debug(
|
|
744
744
|
f"Running step, id: {ctx.function_id}, name: {attributes['name']}"
|
|
745
745
|
)
|
|
746
|
-
return
|
|
746
|
+
return NoResult()
|
|
747
747
|
|
|
748
748
|
stepOutcome = Outcome[R].make(functools.partial(func, *args, **kwargs))
|
|
749
749
|
if retries_allowed:
|
|
@@ -45,7 +45,7 @@ from ._core import (
|
|
|
45
45
|
start_workflow,
|
|
46
46
|
workflow_wrapper,
|
|
47
47
|
)
|
|
48
|
-
from ._queue import Queue,
|
|
48
|
+
from ._queue import Queue, queue_thread
|
|
49
49
|
from ._recovery import recover_pending_workflows, startup_recovery_thread
|
|
50
50
|
from ._registrations import (
|
|
51
51
|
DEFAULT_MAX_RECOVERY_ATTEMPTS,
|
|
@@ -283,6 +283,7 @@ class DBOS:
|
|
|
283
283
|
self.flask: Optional["Flask"] = flask
|
|
284
284
|
self._executor_field: Optional[ThreadPoolExecutor] = None
|
|
285
285
|
self._background_threads: List[threading.Thread] = []
|
|
286
|
+
self._executor_id: str = os.environ.get("DBOS__VMID", "local")
|
|
286
287
|
|
|
287
288
|
# If using FastAPI, set up middleware and lifecycle events
|
|
288
289
|
if self.fastapi is not None:
|
|
@@ -383,7 +384,7 @@ class DBOS:
|
|
|
383
384
|
evt = threading.Event()
|
|
384
385
|
self.stop_events.append(evt)
|
|
385
386
|
bg_queue_thread = threading.Thread(
|
|
386
|
-
target=
|
|
387
|
+
target=queue_thread, args=(evt, self), daemon=True
|
|
387
388
|
)
|
|
388
389
|
bg_queue_thread.start()
|
|
389
390
|
self._background_threads.append(bg_queue_thread)
|
|
@@ -8,6 +8,16 @@ T = TypeVar("T")
|
|
|
8
8
|
R = TypeVar("R")
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
class NoResult:
|
|
12
|
+
_instance: Optional["NoResult"] = None
|
|
13
|
+
__slots__ = ()
|
|
14
|
+
|
|
15
|
+
def __new__(cls, *args: Any, **kwargs: Any) -> "NoResult":
|
|
16
|
+
if not cls._instance:
|
|
17
|
+
cls._instance = super(NoResult, cls).__new__(cls, *args, **kwargs)
|
|
18
|
+
return cls._instance
|
|
19
|
+
|
|
20
|
+
|
|
11
21
|
# define Outcome protocol w/ common composition methods
|
|
12
22
|
class Outcome(Protocol[T]):
|
|
13
23
|
|
|
@@ -28,7 +38,9 @@ class Outcome(Protocol[T]):
|
|
|
28
38
|
exceeded_retries: Callable[[int], BaseException],
|
|
29
39
|
) -> "Outcome[T]": ...
|
|
30
40
|
|
|
31
|
-
def intercept(
|
|
41
|
+
def intercept(
|
|
42
|
+
self, interceptor: Callable[[], Union[NoResult, T]]
|
|
43
|
+
) -> "Outcome[T]": ...
|
|
32
44
|
|
|
33
45
|
def __call__(self) -> Union[T, Coroutine[Any, Any, T]]: ...
|
|
34
46
|
|
|
@@ -58,11 +70,15 @@ class Immediate(Outcome[T]):
|
|
|
58
70
|
return Immediate(lambda: before()(self._func))
|
|
59
71
|
|
|
60
72
|
@staticmethod
|
|
61
|
-
def _intercept(
|
|
73
|
+
def _intercept(
|
|
74
|
+
func: Callable[[], T], interceptor: Callable[[], Union[NoResult, T]]
|
|
75
|
+
) -> T:
|
|
62
76
|
intercepted = interceptor()
|
|
63
|
-
return intercepted if intercepted else func()
|
|
77
|
+
return intercepted if not isinstance(intercepted, NoResult) else func()
|
|
64
78
|
|
|
65
|
-
def intercept(
|
|
79
|
+
def intercept(
|
|
80
|
+
self, interceptor: Callable[[], Union[NoResult, T]]
|
|
81
|
+
) -> "Immediate[T]":
|
|
66
82
|
return Immediate[T](lambda: Immediate._intercept(self._func, interceptor))
|
|
67
83
|
|
|
68
84
|
@staticmethod
|
|
@@ -151,12 +167,12 @@ class Pending(Outcome[T]):
|
|
|
151
167
|
@staticmethod
|
|
152
168
|
async def _intercept(
|
|
153
169
|
func: Callable[[], Coroutine[Any, Any, T]],
|
|
154
|
-
interceptor: Callable[[],
|
|
170
|
+
interceptor: Callable[[], Union[NoResult, T]],
|
|
155
171
|
) -> T:
|
|
156
172
|
intercepted = await asyncio.to_thread(interceptor)
|
|
157
|
-
return intercepted if intercepted else await func()
|
|
173
|
+
return intercepted if not isinstance(intercepted, NoResult) else await func()
|
|
158
174
|
|
|
159
|
-
def intercept(self, interceptor: Callable[[],
|
|
175
|
+
def intercept(self, interceptor: Callable[[], Union[NoResult, T]]) -> "Pending[T]":
|
|
160
176
|
return Pending[T](lambda: Pending._intercept(self._func, interceptor))
|
|
161
177
|
|
|
162
178
|
@staticmethod
|
|
@@ -51,13 +51,13 @@ class Queue:
|
|
|
51
51
|
return start_workflow(dbos, func, self.name, False, *args, **kwargs)
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
def
|
|
54
|
+
def queue_thread(stop_event: threading.Event, dbos: "DBOS") -> None:
|
|
55
55
|
while not stop_event.is_set():
|
|
56
56
|
if stop_event.wait(timeout=1):
|
|
57
57
|
return
|
|
58
58
|
for _, queue in dbos._registry.queue_info_map.items():
|
|
59
59
|
try:
|
|
60
|
-
wf_ids = dbos._sys_db.start_queued_workflows(queue)
|
|
60
|
+
wf_ids = dbos._sys_db.start_queued_workflows(queue, dbos._executor_id)
|
|
61
61
|
for id in wf_ids:
|
|
62
62
|
execute_workflow_by_id(dbos, id)
|
|
63
63
|
except Exception:
|
|
@@ -1104,7 +1104,7 @@ class SystemDatabase:
|
|
|
1104
1104
|
.on_conflict_do_nothing()
|
|
1105
1105
|
)
|
|
1106
1106
|
|
|
1107
|
-
def start_queued_workflows(self, queue: "Queue") -> List[str]:
|
|
1107
|
+
def start_queued_workflows(self, queue: "Queue", executor_id: str) -> List[str]:
|
|
1108
1108
|
start_time_ms = int(time.time() * 1000)
|
|
1109
1109
|
if queue.limiter is not None:
|
|
1110
1110
|
limiter_period_ms = int(queue.limiter["period"] * 1000)
|
|
@@ -1159,7 +1159,7 @@ class SystemDatabase:
|
|
|
1159
1159
|
if len(ret_ids) + num_recent_queries >= queue.limiter["limit"]:
|
|
1160
1160
|
break
|
|
1161
1161
|
|
|
1162
|
-
# To start a function, first set its status to PENDING
|
|
1162
|
+
# To start a function, first set its status to PENDING and update its executor ID
|
|
1163
1163
|
c.execute(
|
|
1164
1164
|
SystemSchema.workflow_status.update()
|
|
1165
1165
|
.where(SystemSchema.workflow_status.c.workflow_uuid == id)
|
|
@@ -1167,7 +1167,10 @@ class SystemDatabase:
|
|
|
1167
1167
|
SystemSchema.workflow_status.c.status
|
|
1168
1168
|
== WorkflowStatusString.ENQUEUED.value
|
|
1169
1169
|
)
|
|
1170
|
-
.values(
|
|
1170
|
+
.values(
|
|
1171
|
+
status=WorkflowStatusString.PENDING.value,
|
|
1172
|
+
executor_id=executor_id,
|
|
1173
|
+
)
|
|
1171
1174
|
)
|
|
1172
1175
|
|
|
1173
1176
|
# Then give it a start time
|
|
@@ -318,6 +318,7 @@ def test_temp_workflow_errors(dbos: DBOS) -> None:
|
|
|
318
318
|
|
|
319
319
|
def test_recovery_workflow(dbos: DBOS) -> None:
|
|
320
320
|
txn_counter: int = 0
|
|
321
|
+
txn_return_none_counter: int = 0
|
|
321
322
|
wf_counter: int = 0
|
|
322
323
|
|
|
323
324
|
@DBOS.workflow()
|
|
@@ -325,6 +326,8 @@ def test_recovery_workflow(dbos: DBOS) -> None:
|
|
|
325
326
|
nonlocal wf_counter
|
|
326
327
|
wf_counter += 1
|
|
327
328
|
res = test_transaction(var2)
|
|
329
|
+
should_be_none = test_transaction_return_none()
|
|
330
|
+
assert should_be_none is None
|
|
328
331
|
return res + var
|
|
329
332
|
|
|
330
333
|
@DBOS.transaction()
|
|
@@ -334,6 +337,13 @@ def test_recovery_workflow(dbos: DBOS) -> None:
|
|
|
334
337
|
txn_counter += 1
|
|
335
338
|
return var2 + str(rows[0][0])
|
|
336
339
|
|
|
340
|
+
@DBOS.transaction()
|
|
341
|
+
def test_transaction_return_none() -> None:
|
|
342
|
+
nonlocal txn_return_none_counter
|
|
343
|
+
DBOS.sql_session.execute(sa.text("SELECT 1")).fetchall()
|
|
344
|
+
txn_return_none_counter += 1
|
|
345
|
+
return
|
|
346
|
+
|
|
337
347
|
wfuuid = str(uuid.uuid4())
|
|
338
348
|
with SetWorkflowID(wfuuid):
|
|
339
349
|
assert test_workflow("bob", "bob") == "bob1bob"
|
|
@@ -367,6 +377,123 @@ def test_recovery_workflow(dbos: DBOS) -> None:
|
|
|
367
377
|
assert workflow_handles[0].get_result() == "bob1bob"
|
|
368
378
|
assert wf_counter == 2
|
|
369
379
|
assert txn_counter == 1
|
|
380
|
+
assert txn_return_none_counter == 1
|
|
381
|
+
|
|
382
|
+
# Test that there was a recovery attempt of this
|
|
383
|
+
stat = workflow_handles[0].get_status()
|
|
384
|
+
assert stat
|
|
385
|
+
assert stat.recovery_attempts == 1
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def test_recovery_workflow_step(dbos: DBOS) -> None:
|
|
389
|
+
step_counter: int = 0
|
|
390
|
+
wf_counter: int = 0
|
|
391
|
+
|
|
392
|
+
@DBOS.workflow()
|
|
393
|
+
def test_workflow(var: str, var2: str) -> str:
|
|
394
|
+
nonlocal wf_counter
|
|
395
|
+
wf_counter += 1
|
|
396
|
+
should_be_none = test_step(var2)
|
|
397
|
+
assert should_be_none is None
|
|
398
|
+
return var
|
|
399
|
+
|
|
400
|
+
@DBOS.step()
|
|
401
|
+
def test_step(var2: str) -> None:
|
|
402
|
+
nonlocal step_counter
|
|
403
|
+
step_counter += 1
|
|
404
|
+
print(f"I'm a test_step {var2}!")
|
|
405
|
+
return
|
|
406
|
+
|
|
407
|
+
wfuuid = str(uuid.uuid4())
|
|
408
|
+
with SetWorkflowID(wfuuid):
|
|
409
|
+
assert test_workflow("bob", "bob") == "bob"
|
|
410
|
+
|
|
411
|
+
dbos._sys_db.wait_for_buffer_flush()
|
|
412
|
+
# Change the workflow status to pending
|
|
413
|
+
dbos._sys_db.update_workflow_status(
|
|
414
|
+
{
|
|
415
|
+
"workflow_uuid": wfuuid,
|
|
416
|
+
"status": "PENDING",
|
|
417
|
+
"name": test_workflow.__qualname__,
|
|
418
|
+
"class_name": None,
|
|
419
|
+
"config_name": None,
|
|
420
|
+
"output": None,
|
|
421
|
+
"error": None,
|
|
422
|
+
"executor_id": None,
|
|
423
|
+
"app_id": None,
|
|
424
|
+
"app_version": None,
|
|
425
|
+
"request": None,
|
|
426
|
+
"recovery_attempts": None,
|
|
427
|
+
"authenticated_user": None,
|
|
428
|
+
"authenticated_roles": None,
|
|
429
|
+
"assumed_role": None,
|
|
430
|
+
"queue_name": None,
|
|
431
|
+
}
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
# Recovery should execute the workflow again but skip the transaction
|
|
435
|
+
workflow_handles = DBOS.recover_pending_workflows()
|
|
436
|
+
assert len(workflow_handles) == 1
|
|
437
|
+
assert workflow_handles[0].get_result() == "bob"
|
|
438
|
+
assert wf_counter == 2
|
|
439
|
+
assert step_counter == 1
|
|
440
|
+
|
|
441
|
+
# Test that there was a recovery attempt of this
|
|
442
|
+
stat = workflow_handles[0].get_status()
|
|
443
|
+
assert stat
|
|
444
|
+
assert stat.recovery_attempts == 1
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def test_workflow_returns_none(dbos: DBOS) -> None:
|
|
448
|
+
wf_counter: int = 0
|
|
449
|
+
|
|
450
|
+
@DBOS.workflow()
|
|
451
|
+
def test_workflow(var: str, var2: str) -> None:
|
|
452
|
+
nonlocal wf_counter
|
|
453
|
+
wf_counter += 1
|
|
454
|
+
assert var == var2 == "bob"
|
|
455
|
+
return
|
|
456
|
+
|
|
457
|
+
wfuuid = str(uuid.uuid4())
|
|
458
|
+
with SetWorkflowID(wfuuid):
|
|
459
|
+
assert test_workflow("bob", "bob") is None
|
|
460
|
+
assert wf_counter == 1
|
|
461
|
+
|
|
462
|
+
dbos._sys_db.wait_for_buffer_flush()
|
|
463
|
+
with SetWorkflowID(wfuuid):
|
|
464
|
+
assert test_workflow("bob", "bob") is None
|
|
465
|
+
assert wf_counter == 2
|
|
466
|
+
|
|
467
|
+
handle: WorkflowHandle[None] = DBOS.retrieve_workflow(wfuuid)
|
|
468
|
+
assert handle.get_result() == None
|
|
469
|
+
assert wf_counter == 2
|
|
470
|
+
|
|
471
|
+
# Change the workflow status to pending
|
|
472
|
+
dbos._sys_db.update_workflow_status(
|
|
473
|
+
{
|
|
474
|
+
"workflow_uuid": wfuuid,
|
|
475
|
+
"status": "PENDING",
|
|
476
|
+
"name": test_workflow.__qualname__,
|
|
477
|
+
"class_name": None,
|
|
478
|
+
"config_name": None,
|
|
479
|
+
"output": None,
|
|
480
|
+
"error": None,
|
|
481
|
+
"executor_id": None,
|
|
482
|
+
"app_id": None,
|
|
483
|
+
"app_version": None,
|
|
484
|
+
"request": None,
|
|
485
|
+
"recovery_attempts": None,
|
|
486
|
+
"authenticated_user": None,
|
|
487
|
+
"authenticated_roles": None,
|
|
488
|
+
"assumed_role": None,
|
|
489
|
+
"queue_name": None,
|
|
490
|
+
}
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
workflow_handles = DBOS.recover_pending_workflows()
|
|
494
|
+
assert len(workflow_handles) == 1
|
|
495
|
+
assert workflow_handles[0].get_result() is None
|
|
496
|
+
assert wf_counter == 3
|
|
370
497
|
|
|
371
498
|
# Test that there was a recovery attempt of this
|
|
372
499
|
stat = workflow_handles[0].get_status()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dbos-0.16.0a2 → dbos-0.17.0}/dbos/_templates/hello/migrations/versions/2024_07_31_180642_init.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|