dbos 1.14.0a6__tar.gz → 1.14.0a8__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.
- {dbos-1.14.0a6 → dbos-1.14.0a8}/PKG-INFO +1 -1
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_debouncer.py +10 -4
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_sys_db.py +6 -1
- {dbos-1.14.0a6 → dbos-1.14.0a8}/pyproject.toml +1 -1
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_debouncer.py +56 -17
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_streaming.py +15 -7
- {dbos-1.14.0a6 → dbos-1.14.0a8}/LICENSE +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/README.md +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/__init__.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/__main__.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_admin_server.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/env.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/script.py.mako +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/01ce9f07bd10_streaming.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/27ac6900c6ad_add_queue_dedup.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/471b60d64126_dbos_migrations.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/66478e1b95e5_consolidate_queues.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/83f3732ae8e7_workflow_timeout.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/933e86bdac6a_add_queue_priority.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/d994145b47b6_consolidate_inputs.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/f4b9b32ba814_functionname_childid_op_outputs.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_app_db.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_classproperty.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_client.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_conductor/conductor.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_conductor/protocol.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_context.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_core.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_croniter.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_dbos.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_dbos_config.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_debug.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_docker_pg_helper.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_error.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_event_loop.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_fastapi.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_flask.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_kafka.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_kafka_message.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_logger.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_migration.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_outcome.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_queue.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_recovery.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_registrations.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_roles.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_scheduler.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_schemas/__init__.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_schemas/application_database.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_schemas/system_database.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_serialization.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_sys_db_postgres.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_sys_db_sqlite.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/README.md +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/__package/main.py.dbos +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_tracer.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_utils.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_workflow_commands.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/cli/_github_init.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/cli/_template_init.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/cli/cli.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/cli/migration.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/dbos-config.schema.json +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/py.typed +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/__init__.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/atexit_no_ctor.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/atexit_no_launch.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/classdefs.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/client_collateral.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/client_worker.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/conftest.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/dupname_classdefs1.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/dupname_classdefsa.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/more_classdefs.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/queuedworkflow.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_admin_server.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_async.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_async_workflow_management.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_classdecorators.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_cli.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_client.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_concurrency.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_config.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_croniter.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_dbos.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_debug.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_docker_secrets.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_failures.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_fastapi.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_fastapi_roles.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_flask.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_kafka.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_outcome.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_package.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_queue.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_scheduler.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_schema_migration.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_singleton.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_spans.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_sqlalchemy.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_workflow_introspection.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/tests/test_workflow_management.py +0 -0
- {dbos-1.14.0a6 → dbos-1.14.0a8}/version/__init__.py +0 -0
@@ -232,7 +232,10 @@ class Debouncer(Generic[P, R]):
|
|
232
232
|
while True:
|
233
233
|
try:
|
234
234
|
# Attempt to enqueue a debouncer for this workflow.
|
235
|
-
|
235
|
+
deduplication_id = (
|
236
|
+
f"{self.options['workflow_name']}-{self.debounce_key}"
|
237
|
+
)
|
238
|
+
with SetEnqueueOptions(deduplication_id=deduplication_id):
|
236
239
|
with SetWorkflowTimeout(None):
|
237
240
|
internal_queue.enqueue(
|
238
241
|
debouncer_workflow,
|
@@ -249,7 +252,7 @@ class Debouncer(Generic[P, R]):
|
|
249
252
|
def get_deduplicated_workflow() -> Optional[str]:
|
250
253
|
return dbos._sys_db.get_deduplicated_workflow(
|
251
254
|
queue_name=internal_queue.name,
|
252
|
-
deduplication_id=
|
255
|
+
deduplication_id=deduplication_id,
|
253
256
|
)
|
254
257
|
|
255
258
|
dedup_wfid = dbos._sys_db.call_function_as_step(
|
@@ -333,10 +336,13 @@ class DebouncerClient:
|
|
333
336
|
while True:
|
334
337
|
try:
|
335
338
|
# Attempt to enqueue a debouncer for this workflow.
|
339
|
+
deduplication_id = (
|
340
|
+
f"{self.debouncer_options['workflow_name']}-{self.debounce_key}"
|
341
|
+
)
|
336
342
|
debouncer_options: EnqueueOptions = {
|
337
343
|
"workflow_name": DEBOUNCER_WORKFLOW_NAME,
|
338
344
|
"queue_name": INTERNAL_QUEUE_NAME,
|
339
|
-
"deduplication_id":
|
345
|
+
"deduplication_id": deduplication_id,
|
340
346
|
}
|
341
347
|
self.client.enqueue(
|
342
348
|
debouncer_options,
|
@@ -353,7 +359,7 @@ class DebouncerClient:
|
|
353
359
|
# If there is already a debouncer, send a message to it.
|
354
360
|
dedup_wfid = self.client._sys_db.get_deduplicated_workflow(
|
355
361
|
queue_name=INTERNAL_QUEUE_NAME,
|
356
|
-
deduplication_id=
|
362
|
+
deduplication_id=deduplication_id,
|
357
363
|
)
|
358
364
|
if dedup_wfid is None:
|
359
365
|
continue
|
@@ -1934,8 +1934,13 @@ class SystemDatabase(ABC):
|
|
1934
1934
|
)
|
1935
1935
|
if self._debug_mode and recorded_output is None:
|
1936
1936
|
raise Exception(
|
1937
|
-
"called
|
1937
|
+
"called writeStream in debug mode without a previous execution"
|
1938
1938
|
)
|
1939
|
+
if recorded_output is not None:
|
1940
|
+
dbos_logger.debug(
|
1941
|
+
f"Replaying writeStream, id: {function_id}, key: {key}"
|
1942
|
+
)
|
1943
|
+
return
|
1939
1944
|
# Find the maximum offset for this workflow_uuid and key combination
|
1940
1945
|
max_offset_result = c.execute(
|
1941
1946
|
sa.select(sa.func.max(SystemSchema.streams.c.offset)).where(
|
@@ -17,17 +17,12 @@ from dbos._queue import Queue
|
|
17
17
|
from dbos._utils import GlobalParams
|
18
18
|
|
19
19
|
|
20
|
-
def workflow(x: int) -> int:
|
21
|
-
return x
|
22
|
-
|
23
|
-
|
24
|
-
async def workflow_async(x: int) -> int:
|
25
|
-
return x
|
26
|
-
|
27
|
-
|
28
20
|
def test_debouncer(dbos: DBOS) -> None:
|
29
21
|
|
30
|
-
DBOS.workflow()
|
22
|
+
@DBOS.workflow()
|
23
|
+
def workflow(x: int) -> int:
|
24
|
+
return x
|
25
|
+
|
31
26
|
first_value, second_value, third_value, fourth_value = 0, 1, 2, 3
|
32
27
|
|
33
28
|
@DBOS.step()
|
@@ -35,17 +30,20 @@ def test_debouncer(dbos: DBOS) -> None:
|
|
35
30
|
return str(uuid.uuid4())
|
36
31
|
|
37
32
|
def debouncer_test() -> None:
|
38
|
-
debouncer = Debouncer.create(workflow, debounce_key="key")
|
39
33
|
|
40
34
|
debounce_period = 2
|
41
35
|
|
36
|
+
debouncer = Debouncer.create(workflow, debounce_key="key")
|
42
37
|
first_handle = debouncer.debounce(debounce_period, first_value)
|
38
|
+
debouncer = Debouncer.create(workflow, debounce_key="key")
|
43
39
|
second_handle = debouncer.debounce(debounce_period, second_value)
|
44
40
|
assert first_handle.workflow_id == second_handle.workflow_id
|
45
41
|
assert first_handle.get_result() == second_value
|
46
42
|
assert second_handle.get_result() == second_value
|
47
43
|
|
44
|
+
debouncer = Debouncer.create(workflow, debounce_key="key")
|
48
45
|
third_handle = debouncer.debounce(debounce_period, third_value)
|
46
|
+
debouncer = Debouncer.create(workflow, debounce_key="key")
|
49
47
|
fourth_handle = debouncer.debounce(debounce_period, fourth_value)
|
50
48
|
assert third_handle.workflow_id != first_handle.workflow_id
|
51
49
|
assert third_handle.workflow_id == fourth_handle.workflow_id
|
@@ -76,7 +74,10 @@ def test_debouncer(dbos: DBOS) -> None:
|
|
76
74
|
|
77
75
|
def test_debouncer_timeout(dbos: DBOS) -> None:
|
78
76
|
|
79
|
-
DBOS.workflow()
|
77
|
+
@DBOS.workflow()
|
78
|
+
def workflow(x: int) -> int:
|
79
|
+
return x
|
80
|
+
|
80
81
|
first_value, second_value, third_value, fourth_value = 0, 1, 2, 3
|
81
82
|
|
82
83
|
# Set a huge period but small timeout, verify workflows start after the timeout
|
@@ -115,9 +116,38 @@ def test_debouncer_timeout(dbos: DBOS) -> None:
|
|
115
116
|
assert second_handle.get_result() == second_value
|
116
117
|
|
117
118
|
|
119
|
+
def test_multiple_debouncers(dbos: DBOS) -> None:
|
120
|
+
|
121
|
+
@DBOS.workflow()
|
122
|
+
def workflow(x: int) -> int:
|
123
|
+
return x
|
124
|
+
|
125
|
+
first_value, second_value, third_value, fourth_value = 0, 1, 2, 3
|
126
|
+
|
127
|
+
# Set a huge period but small timeout, verify workflows start after the timeout
|
128
|
+
debouncer_one = Debouncer.create(workflow, debounce_key="key_one")
|
129
|
+
debouncer_two = Debouncer.create(workflow, debounce_key="key_two")
|
130
|
+
debounce_period = 2
|
131
|
+
|
132
|
+
first_handle = debouncer_one.debounce(debounce_period, first_value)
|
133
|
+
second_handle = debouncer_one.debounce(debounce_period, second_value)
|
134
|
+
third_handle = debouncer_two.debounce(debounce_period, third_value)
|
135
|
+
fourth_handle = debouncer_two.debounce(debounce_period, fourth_value)
|
136
|
+
assert first_handle.workflow_id == second_handle.workflow_id
|
137
|
+
assert first_handle.workflow_id != third_handle.workflow_id
|
138
|
+
assert third_handle.workflow_id == fourth_handle.workflow_id
|
139
|
+
assert first_handle.get_result() == second_value
|
140
|
+
assert second_handle.get_result() == second_value
|
141
|
+
assert third_handle.get_result() == fourth_value
|
142
|
+
assert fourth_handle.get_result() == fourth_value
|
143
|
+
|
144
|
+
|
118
145
|
def test_debouncer_queue(dbos: DBOS) -> None:
|
119
146
|
|
120
|
-
DBOS.workflow()
|
147
|
+
@DBOS.workflow()
|
148
|
+
def workflow(x: int) -> int:
|
149
|
+
return x
|
150
|
+
|
121
151
|
first_value, second_value, third_value, fourth_value = 0, 1, 2, 3
|
122
152
|
queue = Queue("test-queue")
|
123
153
|
|
@@ -166,7 +196,10 @@ def test_debouncer_queue(dbos: DBOS) -> None:
|
|
166
196
|
@pytest.mark.asyncio
|
167
197
|
async def test_debouncer_async(dbos: DBOS) -> None:
|
168
198
|
|
169
|
-
DBOS.workflow()
|
199
|
+
@DBOS.workflow()
|
200
|
+
async def workflow_async(x: int) -> int:
|
201
|
+
return x
|
202
|
+
|
170
203
|
first_value, second_value, third_value, fourth_value = 0, 1, 2, 3
|
171
204
|
|
172
205
|
debouncer = Debouncer.create_async(workflow_async, debounce_key="key")
|
@@ -188,12 +221,15 @@ async def test_debouncer_async(dbos: DBOS) -> None:
|
|
188
221
|
|
189
222
|
def test_debouncer_client(dbos: DBOS, client: DBOSClient) -> None:
|
190
223
|
|
191
|
-
DBOS.workflow()
|
224
|
+
@DBOS.workflow()
|
225
|
+
def workflow(x: int) -> int:
|
226
|
+
return x
|
227
|
+
|
192
228
|
first_value, second_value, third_value, fourth_value = 0, 1, 2, 3
|
193
229
|
queue = Queue("test-queue")
|
194
230
|
|
195
231
|
options: EnqueueOptions = {
|
196
|
-
"workflow_name": workflow.
|
232
|
+
"workflow_name": workflow.__qualname__,
|
197
233
|
"queue_name": queue.name,
|
198
234
|
}
|
199
235
|
debouncer = DebouncerClient(client, options, debounce_key="key")
|
@@ -230,12 +266,15 @@ def test_debouncer_client(dbos: DBOS, client: DBOSClient) -> None:
|
|
230
266
|
@pytest.mark.asyncio
|
231
267
|
async def test_debouncer_client_async(dbos: DBOS, client: DBOSClient) -> None:
|
232
268
|
|
233
|
-
DBOS.workflow()
|
269
|
+
@DBOS.workflow()
|
270
|
+
async def workflow_async(x: int) -> int:
|
271
|
+
return x
|
272
|
+
|
234
273
|
first_value, second_value, third_value, fourth_value = 0, 1, 2, 3
|
235
274
|
queue = Queue("test-queue")
|
236
275
|
|
237
276
|
options: EnqueueOptions = {
|
238
|
-
"workflow_name": workflow_async.
|
277
|
+
"workflow_name": workflow_async.__qualname__,
|
239
278
|
"queue_name": queue.name,
|
240
279
|
}
|
241
280
|
debouncer = DebouncerClient(client, options, debounce_key="key")
|
@@ -231,16 +231,19 @@ def test_stream_error_cases(dbos: DBOS) -> None:
|
|
231
231
|
def test_stream_workflow_recovery(dbos: DBOS) -> None:
|
232
232
|
"""Test that stream operations are properly recovered during workflow replay."""
|
233
233
|
|
234
|
-
|
234
|
+
workflow_call_count = 0
|
235
|
+
step_call_count = 0
|
235
236
|
|
236
237
|
@DBOS.step()
|
237
238
|
def counting_step() -> int:
|
238
|
-
nonlocal
|
239
|
-
|
240
|
-
return
|
239
|
+
nonlocal step_call_count
|
240
|
+
step_call_count += 1
|
241
|
+
return step_call_count
|
241
242
|
|
242
243
|
@DBOS.workflow()
|
243
244
|
def recovery_test_workflow() -> None:
|
245
|
+
nonlocal workflow_call_count
|
246
|
+
workflow_call_count += 1
|
244
247
|
count1 = counting_step()
|
245
248
|
DBOS.write_stream("recovery_stream", f"step_{count1}")
|
246
249
|
|
@@ -254,13 +257,18 @@ def test_stream_workflow_recovery(dbos: DBOS) -> None:
|
|
254
257
|
with SetWorkflowID(wfid):
|
255
258
|
recovery_test_workflow()
|
256
259
|
|
260
|
+
# Validate stream contents
|
261
|
+
values = list(DBOS.read_stream(wfid, "recovery_stream"))
|
262
|
+
assert values == ["step_1", "step_2"]
|
263
|
+
|
257
264
|
# Reset call count and run the same workflow ID again (should replay)
|
258
|
-
|
265
|
+
dbos._sys_db.update_workflow_outcome(wfid, "PENDING")
|
259
266
|
with SetWorkflowID(wfid):
|
260
267
|
recovery_test_workflow()
|
261
268
|
|
262
|
-
# The
|
263
|
-
assert
|
269
|
+
# The workflow should have been called again
|
270
|
+
assert workflow_call_count == 2
|
271
|
+
assert step_call_count == 2
|
264
272
|
|
265
273
|
# Stream should still be readable and contain the same values
|
266
274
|
values = list(DBOS.read_stream(wfid, "recovery_stream"))
|
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-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/27ac6900c6ad_add_queue_dedup.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/471b60d64126_dbos_migrations.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/50f3227f0b4b_fix_job_queue.py
RENAMED
File without changes
|
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/66478e1b95e5_consolidate_queues.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/83f3732ae8e7_workflow_timeout.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/933e86bdac6a_add_queue_priority.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/a3b18ad34abe_added_triggers.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/d76646551a6b_job_queue_limiter.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/d76646551a6c_workflow_queue.py
RENAMED
File without changes
|
{dbos-1.14.0a6 → dbos-1.14.0a8}/dbos/_alembic_migrations/versions/d994145b47b6_consolidate_inputs.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
|
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
|
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
|