dbos 0.17.0a2__tar.gz → 0.17.0a4__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.17.0a2 → dbos-0.17.0a4}/PKG-INFO +1 -1
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_core.py +6 -4
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_outcome.py +21 -15
- {dbos-0.17.0a2 → dbos-0.17.0a4}/pyproject.toml +1 -1
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_dbos.py +70 -1
- {dbos-0.17.0a2 → dbos-0.17.0a4}/LICENSE +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/README.md +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/__init__.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_admin_server.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_app_db.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_classproperty.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_context.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_croniter.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_dbos.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_dbos_config.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_error.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_fastapi.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_flask.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_kafka.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_kafka_message.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_logger.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/env.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/script.py.mako +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_queue.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_recovery.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_registrations.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_request.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_roles.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_scheduler.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_schemas/__init__.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_schemas/application_database.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_schemas/system_database.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_serialization.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_sys_db.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/README.md +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/__package/__init__.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/__package/main.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/__package/schema.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/alembic.ini +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/dbos-config.yaml.dbos +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/migrations/env.py.dbos +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/migrations/script.py.mako +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/migrations/versions/2024_07_31_180642_init.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_templates/hello/start_postgres_docker.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/_tracer.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/cli.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/dbos-config.schema.json +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/dbos/py.typed +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/__init__.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/atexit_no_ctor.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/atexit_no_launch.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/classdefs.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/conftest.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/more_classdefs.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_admin_server.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_async.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_classdecorators.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_concurrency.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_config.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_croniter.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_failures.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_fastapi.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_fastapi_roles.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_flask.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_kafka.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_outcome.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_package.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_queue.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_scheduler.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_schema_migration.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_singleton.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/tests/test_spans.py +0 -0
- {dbos-0.17.0a2 → dbos-0.17.0a4}/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
|
|
@@ -734,14 +734,16 @@ def decorate_step(
|
|
|
734
734
|
)
|
|
735
735
|
raise deserialized_error
|
|
736
736
|
elif recorded_output["output"] is not None:
|
|
737
|
-
return
|
|
737
|
+
return cast(
|
|
738
|
+
R, _serialization.deserialize(recorded_output["output"])
|
|
739
|
+
)
|
|
738
740
|
else:
|
|
739
741
|
raise Exception("Output and error are both None")
|
|
740
742
|
else:
|
|
741
743
|
dbos.logger.debug(
|
|
742
744
|
f"Running step, id: {ctx.function_id}, name: {attributes['name']}"
|
|
743
745
|
)
|
|
744
|
-
return
|
|
746
|
+
return NoResult()
|
|
745
747
|
|
|
746
748
|
stepOutcome = Outcome[R].make(functools.partial(func, *args, **kwargs))
|
|
747
749
|
if retries_allowed:
|
|
@@ -4,12 +4,20 @@ import inspect
|
|
|
4
4
|
import time
|
|
5
5
|
from typing import Any, Callable, Coroutine, Optional, Protocol, TypeVar, Union, cast
|
|
6
6
|
|
|
7
|
-
from . import _serialization
|
|
8
|
-
|
|
9
7
|
T = TypeVar("T")
|
|
10
8
|
R = TypeVar("R")
|
|
11
9
|
|
|
12
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
|
+
|
|
13
21
|
# define Outcome protocol w/ common composition methods
|
|
14
22
|
class Outcome(Protocol[T]):
|
|
15
23
|
|
|
@@ -30,7 +38,9 @@ class Outcome(Protocol[T]):
|
|
|
30
38
|
exceeded_retries: Callable[[int], BaseException],
|
|
31
39
|
) -> "Outcome[T]": ...
|
|
32
40
|
|
|
33
|
-
def intercept(
|
|
41
|
+
def intercept(
|
|
42
|
+
self, interceptor: Callable[[], Union[NoResult, T]]
|
|
43
|
+
) -> "Outcome[T]": ...
|
|
34
44
|
|
|
35
45
|
def __call__(self) -> Union[T, Coroutine[Any, Any, T]]: ...
|
|
36
46
|
|
|
@@ -61,14 +71,14 @@ class Immediate(Outcome[T]):
|
|
|
61
71
|
|
|
62
72
|
@staticmethod
|
|
63
73
|
def _intercept(
|
|
64
|
-
func: Callable[[], T], interceptor: Callable[[],
|
|
74
|
+
func: Callable[[], T], interceptor: Callable[[], Union[NoResult, T]]
|
|
65
75
|
) -> T:
|
|
66
76
|
intercepted = interceptor()
|
|
67
|
-
return (
|
|
68
|
-
cast(T, _serialization.deserialize(intercepted)) if intercepted else func()
|
|
69
|
-
)
|
|
77
|
+
return intercepted if not isinstance(intercepted, NoResult) else func()
|
|
70
78
|
|
|
71
|
-
def intercept(
|
|
79
|
+
def intercept(
|
|
80
|
+
self, interceptor: Callable[[], Union[NoResult, T]]
|
|
81
|
+
) -> "Immediate[T]":
|
|
72
82
|
return Immediate[T](lambda: Immediate._intercept(self._func, interceptor))
|
|
73
83
|
|
|
74
84
|
@staticmethod
|
|
@@ -157,16 +167,12 @@ class Pending(Outcome[T]):
|
|
|
157
167
|
@staticmethod
|
|
158
168
|
async def _intercept(
|
|
159
169
|
func: Callable[[], Coroutine[Any, Any, T]],
|
|
160
|
-
interceptor: Callable[[],
|
|
170
|
+
interceptor: Callable[[], Union[NoResult, T]],
|
|
161
171
|
) -> T:
|
|
162
172
|
intercepted = await asyncio.to_thread(interceptor)
|
|
163
|
-
return (
|
|
164
|
-
cast(T, _serialization.deserialize(intercepted))
|
|
165
|
-
if intercepted
|
|
166
|
-
else await func()
|
|
167
|
-
)
|
|
173
|
+
return intercepted if not isinstance(intercepted, NoResult) else await func()
|
|
168
174
|
|
|
169
|
-
def intercept(self, interceptor: Callable[[],
|
|
175
|
+
def intercept(self, interceptor: Callable[[], Union[NoResult, T]]) -> "Pending[T]":
|
|
170
176
|
return Pending[T](lambda: Pending._intercept(self._func, interceptor))
|
|
171
177
|
|
|
172
178
|
@staticmethod
|
|
@@ -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,7 @@ 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
|
|
370
381
|
|
|
371
382
|
# Test that there was a recovery attempt of this
|
|
372
383
|
stat = workflow_handles[0].get_status()
|
|
@@ -382,7 +393,8 @@ def test_recovery_workflow_step(dbos: DBOS) -> None:
|
|
|
382
393
|
def test_workflow(var: str, var2: str) -> str:
|
|
383
394
|
nonlocal wf_counter
|
|
384
395
|
wf_counter += 1
|
|
385
|
-
test_step(var2)
|
|
396
|
+
should_be_none = test_step(var2)
|
|
397
|
+
assert should_be_none is None
|
|
386
398
|
return var
|
|
387
399
|
|
|
388
400
|
@DBOS.step()
|
|
@@ -432,6 +444,63 @@ def test_recovery_workflow_step(dbos: DBOS) -> None:
|
|
|
432
444
|
assert stat.recovery_attempts == 1
|
|
433
445
|
|
|
434
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
|
|
497
|
+
|
|
498
|
+
# Test that there was a recovery attempt of this
|
|
499
|
+
stat = workflow_handles[0].get_status()
|
|
500
|
+
assert stat
|
|
501
|
+
assert stat.recovery_attempts == 1
|
|
502
|
+
|
|
503
|
+
|
|
435
504
|
def test_recovery_temp_workflow(dbos: DBOS) -> None:
|
|
436
505
|
txn_counter: int = 0
|
|
437
506
|
|
|
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.17.0a2 → dbos-0.17.0a4}/dbos/_migrations/versions/5c361fc04708_added_system_tables.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
|
{dbos-0.17.0a2 → dbos-0.17.0a4}/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
|