dbos 1.13.0a8__tar.gz → 1.13.2__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.

Files changed (116) hide show
  1. {dbos-1.13.0a8 → dbos-1.13.2}/PKG-INFO +1 -1
  2. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_client.py +1 -1
  3. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_sys_db.py +6 -1
  4. {dbos-1.13.0a8 → dbos-1.13.2}/pyproject.toml +1 -1
  5. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_config.py +6 -0
  6. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_package.py +15 -21
  7. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_streaming.py +15 -7
  8. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_workflow_management.py +2 -2
  9. {dbos-1.13.0a8 → dbos-1.13.2}/LICENSE +0 -0
  10. {dbos-1.13.0a8 → dbos-1.13.2}/README.md +0 -0
  11. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/__init__.py +0 -0
  12. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/__main__.py +0 -0
  13. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_admin_server.py +0 -0
  14. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/env.py +0 -0
  15. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/script.py.mako +0 -0
  16. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/01ce9f07bd10_streaming.py +0 -0
  17. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  18. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/27ac6900c6ad_add_queue_dedup.py +0 -0
  19. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/471b60d64126_dbos_migrations.py +0 -0
  20. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  21. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  22. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/66478e1b95e5_consolidate_queues.py +0 -0
  23. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/83f3732ae8e7_workflow_timeout.py +0 -0
  24. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/933e86bdac6a_add_queue_priority.py +0 -0
  25. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  26. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  27. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  28. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/d994145b47b6_consolidate_inputs.py +0 -0
  29. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  30. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_alembic_migrations/versions/f4b9b32ba814_functionname_childid_op_outputs.py +0 -0
  31. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_app_db.py +0 -0
  32. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_classproperty.py +0 -0
  33. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_conductor/conductor.py +0 -0
  34. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_conductor/protocol.py +0 -0
  35. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_context.py +0 -0
  36. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_core.py +0 -0
  37. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_croniter.py +0 -0
  38. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_dbos.py +0 -0
  39. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_dbos_config.py +0 -0
  40. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_debug.py +0 -0
  41. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_docker_pg_helper.py +0 -0
  42. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_error.py +0 -0
  43. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_event_loop.py +0 -0
  44. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_fastapi.py +0 -0
  45. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_flask.py +0 -0
  46. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_kafka.py +0 -0
  47. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_kafka_message.py +0 -0
  48. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_logger.py +0 -0
  49. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_migration.py +0 -0
  50. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_outcome.py +0 -0
  51. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_queue.py +0 -0
  52. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_recovery.py +0 -0
  53. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_registrations.py +0 -0
  54. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_roles.py +0 -0
  55. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_scheduler.py +0 -0
  56. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_schemas/__init__.py +0 -0
  57. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_schemas/application_database.py +0 -0
  58. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_schemas/system_database.py +0 -0
  59. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_serialization.py +0 -0
  60. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_sys_db_postgres.py +0 -0
  61. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_sys_db_sqlite.py +0 -0
  62. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/README.md +0 -0
  63. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  64. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/__package/main.py.dbos +0 -0
  65. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  66. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  67. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  68. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  69. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  70. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  71. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  72. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_tracer.py +0 -0
  73. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_utils.py +0 -0
  74. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/_workflow_commands.py +0 -0
  75. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/cli/_github_init.py +0 -0
  76. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/cli/_template_init.py +0 -0
  77. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/cli/cli.py +0 -0
  78. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/cli/migration.py +0 -0
  79. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/dbos-config.schema.json +0 -0
  80. {dbos-1.13.0a8 → dbos-1.13.2}/dbos/py.typed +0 -0
  81. {dbos-1.13.0a8 → dbos-1.13.2}/tests/__init__.py +0 -0
  82. {dbos-1.13.0a8 → dbos-1.13.2}/tests/atexit_no_ctor.py +0 -0
  83. {dbos-1.13.0a8 → dbos-1.13.2}/tests/atexit_no_launch.py +0 -0
  84. {dbos-1.13.0a8 → dbos-1.13.2}/tests/classdefs.py +0 -0
  85. {dbos-1.13.0a8 → dbos-1.13.2}/tests/client_collateral.py +0 -0
  86. {dbos-1.13.0a8 → dbos-1.13.2}/tests/client_worker.py +0 -0
  87. {dbos-1.13.0a8 → dbos-1.13.2}/tests/conftest.py +0 -0
  88. {dbos-1.13.0a8 → dbos-1.13.2}/tests/dupname_classdefs1.py +0 -0
  89. {dbos-1.13.0a8 → dbos-1.13.2}/tests/dupname_classdefsa.py +0 -0
  90. {dbos-1.13.0a8 → dbos-1.13.2}/tests/more_classdefs.py +0 -0
  91. {dbos-1.13.0a8 → dbos-1.13.2}/tests/queuedworkflow.py +0 -0
  92. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_admin_server.py +0 -0
  93. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_async.py +0 -0
  94. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_async_workflow_management.py +0 -0
  95. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_classdecorators.py +0 -0
  96. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_cli.py +0 -0
  97. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_client.py +0 -0
  98. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_concurrency.py +0 -0
  99. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_croniter.py +0 -0
  100. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_dbos.py +0 -0
  101. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_debug.py +0 -0
  102. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_docker_secrets.py +0 -0
  103. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_failures.py +0 -0
  104. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_fastapi.py +0 -0
  105. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_fastapi_roles.py +0 -0
  106. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_flask.py +0 -0
  107. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_kafka.py +0 -0
  108. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_outcome.py +0 -0
  109. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_queue.py +0 -0
  110. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_scheduler.py +0 -0
  111. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_schema_migration.py +0 -0
  112. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_singleton.py +0 -0
  113. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_spans.py +0 -0
  114. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_sqlalchemy.py +0 -0
  115. {dbos-1.13.0a8 → dbos-1.13.2}/tests/test_workflow_introspection.py +0 -0
  116. {dbos-1.13.0a8 → dbos-1.13.2}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 1.13.0a8
3
+ Version: 1.13.2
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -241,7 +241,7 @@ class DBOSClient:
241
241
  return WorkflowHandleClientPolling[R](workflow_id, self._sys_db)
242
242
 
243
243
  async def retrieve_workflow_async(self, workflow_id: str) -> WorkflowHandleAsync[R]:
244
- status = asyncio.to_thread(get_workflow, self._sys_db, workflow_id)
244
+ status = await asyncio.to_thread(get_workflow, self._sys_db, workflow_id)
245
245
  if status is None:
246
246
  raise DBOSNonExistentWorkflowError(workflow_id)
247
247
  return WorkflowHandleClientAsyncPolling[R](workflow_id, self._sys_db)
@@ -1901,8 +1901,13 @@ class SystemDatabase(ABC):
1901
1901
  )
1902
1902
  if self._debug_mode and recorded_output is None:
1903
1903
  raise Exception(
1904
- "called set_event in debug mode without a previous execution"
1904
+ "called writeStream in debug mode without a previous execution"
1905
1905
  )
1906
+ if recorded_output is not None:
1907
+ dbos_logger.debug(
1908
+ f"Replaying writeStream, id: {function_id}, key: {key}"
1909
+ )
1910
+ return
1906
1911
  # Find the maximum offset for this workflow_uuid and key combination
1907
1912
  max_offset_result = c.execute(
1908
1913
  sa.select(sa.func.max(SystemSchema.streams.c.offset)).where(
@@ -27,7 +27,7 @@ dependencies = [
27
27
  ]
28
28
  requires-python = ">=3.9"
29
29
  readme = "README.md"
30
- version = "1.13.0a8"
30
+ version = "1.13.2"
31
31
 
32
32
  [project.license]
33
33
  text = "MIT"
@@ -939,6 +939,7 @@ def test_overwrite_config(mocker):
939
939
  assert "env" not in config
940
940
 
941
941
  del os.environ["DBOS_DATABASE_URL"]
942
+ del os.environ["DBOS_SYSTEM_DATABASE_URL"]
942
943
 
943
944
 
944
945
  def test_overwrite_config_minimal(mocker):
@@ -985,6 +986,7 @@ def test_overwrite_config_minimal(mocker):
985
986
  assert "env" not in config
986
987
 
987
988
  del os.environ["DBOS_DATABASE_URL"]
989
+ del os.environ["DBOS_SYSTEM_DATABASE_URL"]
988
990
 
989
991
 
990
992
  def test_overwrite_config_has_telemetry(mocker):
@@ -1033,6 +1035,7 @@ def test_overwrite_config_has_telemetry(mocker):
1033
1035
  assert "env" not in config
1034
1036
 
1035
1037
  del os.environ["DBOS_DATABASE_URL"]
1038
+ del os.environ["DBOS_SYSTEM_DATABASE_URL"]
1036
1039
 
1037
1040
 
1038
1041
  # Not expected in practice, but exercise the code path
@@ -1068,6 +1071,7 @@ def test_overwrite_config_no_telemetry_in_file(mocker):
1068
1071
  }
1069
1072
 
1070
1073
  del os.environ["DBOS_DATABASE_URL"]
1074
+ del os.environ["DBOS_SYSTEM_DATABASE_URL"]
1071
1075
 
1072
1076
 
1073
1077
  # Not expected in practice, but exercise the code path
@@ -1109,6 +1113,7 @@ def test_overwrite_config_no_otlp_in_file(mocker):
1109
1113
  assert "logs" not in config["telemetry"]
1110
1114
 
1111
1115
  del os.environ["DBOS_DATABASE_URL"]
1116
+ del os.environ["DBOS_SYSTEM_DATABASE_URL"]
1112
1117
 
1113
1118
 
1114
1119
  def test_overwrite_config_with_provided_database_url(mocker):
@@ -1156,6 +1161,7 @@ def test_overwrite_config_with_provided_database_url(mocker):
1156
1161
  assert "env" not in config
1157
1162
 
1158
1163
  del os.environ["DBOS_DATABASE_URL"]
1164
+ del os.environ["DBOS_SYSTEM_DATABASE_URL"]
1159
1165
 
1160
1166
 
1161
1167
  def test_overwrite_config_missing_dbos_database_url(mocker):
@@ -175,22 +175,24 @@ def test_workflow_commands(config: DBOSConfig) -> None:
175
175
  db_url = config["system_database_url"]
176
176
  else:
177
177
  db_url = (
178
- sa.make_url(config["application_database_url"])
178
+ sa.make_url(config["system_database_url"])
179
179
  .set(database="dbos_toolbox")
180
180
  .render_as_string(hide_password=False)
181
181
  )
182
182
  with tempfile.TemporaryDirectory() as temp_path:
183
183
  env = os.environ.copy()
184
- env["DBOS_DATABASE_URL"] = db_url
184
+ env["DBOS_SYSTEM_DATABASE_URL"] = db_url
185
185
  subprocess.check_call(
186
186
  ["dbos", "init", "--template", "dbos-toolbox"],
187
187
  cwd=temp_path,
188
188
  env=env,
189
189
  )
190
- subprocess.check_call(["dbos", "reset", "-y", "-D", db_url], cwd=temp_path)
190
+ subprocess.check_call(
191
+ ["dbos", "reset", "-y", "--sys-db-url", db_url], cwd=temp_path
192
+ )
191
193
 
192
194
  # Get some workflows enqueued on the toolbox, then kill the toolbox
193
- process = subprocess.Popen(["dbos", "start"], cwd=temp_path, env=env)
195
+ process = subprocess.Popen(["python3", "main.py"], cwd=temp_path, env=env)
194
196
  try:
195
197
  session = requests.Session()
196
198
  for i in range(10):
@@ -209,25 +211,25 @@ def test_workflow_commands(config: DBOSConfig) -> None:
209
211
  time.sleep(1) # So the queued workflows can start
210
212
  finally:
211
213
  # Because the toolbox steps sleep for 5 seconds, all the steps should be PENDING
212
- os.kill(process.pid, signal.SIGINT)
214
+ os.kill(process.pid, signal.SIGKILL)
213
215
  process.wait()
214
216
 
215
217
  # Verify the output is valid JSON
216
218
  output = subprocess.check_output(
217
- ["dbos", "workflow", "list", "--db-url", db_url], cwd=temp_path
219
+ ["dbos", "workflow", "list", "--sys-db-url", db_url], cwd=temp_path
218
220
  )
219
221
  data = json.loads(output)
220
222
  assert isinstance(data, list) and len(data) == 10
221
223
 
222
224
  # Verify the output is valid JSON
223
225
  output = subprocess.check_output(
224
- ["dbos", "workflow", "queue", "list", "--db-url", db_url], cwd=temp_path
226
+ ["dbos", "workflow", "queue", "list", "--sys-db-url", db_url], cwd=temp_path
225
227
  )
226
228
  workflows = json.loads(output)
227
229
  assert isinstance(workflows, list) and len(workflows) == 10
228
230
  for wf in workflows:
229
231
  output = subprocess.check_output(
230
- ["dbos", "workflow", "get", wf["workflow_id"], "--db-url", db_url],
232
+ ["dbos", "workflow", "get", wf["workflow_id"], "--sys-db-url", db_url],
231
233
  cwd=temp_path,
232
234
  )
233
235
  get_wf_data = json.loads(output)
@@ -237,7 +239,7 @@ def test_workflow_commands(config: DBOSConfig) -> None:
237
239
  # workflow ID is a preffix to each step ID
238
240
  wf_id = "-".join(workflows[0]["workflow_id"].split("-")[:-1])
239
241
  get_steps_output = subprocess.check_output(
240
- ["dbos", "workflow", "steps", wf_id, "--db-url", db_url], cwd=temp_path
242
+ ["dbos", "workflow", "steps", wf_id, "--sys-db-url", db_url], cwd=temp_path
241
243
  )
242
244
  get_steps_data = json.loads(get_steps_output)
243
245
  assert isinstance(get_steps_data, list)
@@ -310,8 +312,7 @@ def test_workflow_commands(config: DBOSConfig) -> None:
310
312
 
311
313
  # verify the forked workflow data with get command
312
314
  output = subprocess.check_output(
313
- ["dbos", "workflow", "get", custom_fork_id, "--db-url", db_url],
314
- cwd=temp_path,
315
+ ["dbos", "workflow", "get", custom_fork_id], cwd=temp_path, env=env
315
316
  )
316
317
  custom_fork_get_data = json.loads(output)
317
318
  assert isinstance(custom_fork_get_data, dict)
@@ -339,15 +340,9 @@ def test_workflow_commands(config: DBOSConfig) -> None:
339
340
 
340
341
  # verify the forked workflow data with get command and check application version
341
342
  output = subprocess.check_output(
342
- [
343
- "dbos",
344
- "workflow",
345
- "get",
346
- version_fork_data["workflow_id"],
347
- "--db-url",
348
- db_url,
349
- ],
343
+ ["dbos", "workflow", "get", version_fork_data["workflow_id"]],
350
344
  cwd=temp_path,
345
+ env=env,
351
346
  )
352
347
  version_fork_get_data = json.loads(output)
353
348
  assert isinstance(version_fork_get_data, dict)
@@ -379,8 +374,7 @@ def test_workflow_commands(config: DBOSConfig) -> None:
379
374
 
380
375
  # verify the forked workflow data with get command and check both ID and application version
381
376
  output = subprocess.check_output(
382
- ["dbos", "workflow", "get", custom_fork_id2, "--db-url", db_url],
383
- cwd=temp_path,
377
+ ["dbos", "workflow", "get", custom_fork_id2], cwd=temp_path, env=env
384
378
  )
385
379
  combined_fork_get_data = json.loads(output)
386
380
  assert isinstance(combined_fork_get_data, dict)
@@ -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
- call_count = 0
234
+ workflow_call_count = 0
235
+ step_call_count = 0
235
236
 
236
237
  @DBOS.step()
237
238
  def counting_step() -> int:
238
- nonlocal call_count
239
- call_count += 1
240
- return call_count
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
- call_count = 0
265
+ dbos._sys_db.update_workflow_outcome(wfid, "PENDING")
259
266
  with SetWorkflowID(wfid):
260
267
  recovery_test_workflow()
261
268
 
262
- # The counting step should not have been called again (replayed from recorded results)
263
- assert call_count == 0
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"))
@@ -738,8 +738,8 @@ def test_global_timeout(dbos: DBOS) -> None:
738
738
  num_workflows = 10
739
739
  handles = [DBOS.start_workflow(blocked_workflow) for _ in range(num_workflows)]
740
740
 
741
- # Wait one second, start one final workflow, then timeout all workflows started more than one second ago
742
- time.sleep(1)
741
+ # Wait two seconds, start one final workflow, then timeout all workflows started more than one second ago
742
+ time.sleep(2)
743
743
  final_handle = DBOS.start_workflow(blocked_workflow)
744
744
  cutoff_epoch_timestamp_ms = int(time.time() * 1000) - 1000
745
745
  global_timeout(dbos, cutoff_epoch_timestamp_ms)
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