dbos 0.24.0a5__tar.gz → 0.24.0a6__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 (98) hide show
  1. {dbos-0.24.0a5 → dbos-0.24.0a6}/PKG-INFO +1 -1
  2. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_core.py +3 -1
  3. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_error.py +9 -3
  4. {dbos-0.24.0a5 → dbos-0.24.0a6}/pyproject.toml +1 -1
  5. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_failures.py +69 -3
  6. {dbos-0.24.0a5 → dbos-0.24.0a6}/LICENSE +0 -0
  7. {dbos-0.24.0a5 → dbos-0.24.0a6}/README.md +0 -0
  8. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/__init__.py +0 -0
  9. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/__main__.py +0 -0
  10. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_admin_server.py +0 -0
  11. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_app_db.py +0 -0
  12. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_classproperty.py +0 -0
  13. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_cloudutils/authentication.py +0 -0
  14. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_cloudutils/cloudutils.py +0 -0
  15. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_cloudutils/databases.py +0 -0
  16. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_conductor/conductor.py +0 -0
  17. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_conductor/protocol.py +0 -0
  18. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_context.py +0 -0
  19. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_croniter.py +0 -0
  20. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_db_wizard.py +0 -0
  21. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_dbos.py +0 -0
  22. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_dbos_config.py +0 -0
  23. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_debug.py +0 -0
  24. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_fastapi.py +0 -0
  25. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_flask.py +0 -0
  26. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_kafka.py +0 -0
  27. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_kafka_message.py +0 -0
  28. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_logger.py +0 -0
  29. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/env.py +0 -0
  30. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/script.py.mako +0 -0
  31. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  32. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  33. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  34. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  35. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  36. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  37. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  38. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_outcome.py +0 -0
  39. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_queue.py +0 -0
  40. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_recovery.py +0 -0
  41. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_registrations.py +0 -0
  42. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_request.py +0 -0
  43. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_roles.py +0 -0
  44. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_scheduler.py +0 -0
  45. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_schemas/__init__.py +0 -0
  46. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_schemas/application_database.py +0 -0
  47. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_schemas/system_database.py +0 -0
  48. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_serialization.py +0 -0
  49. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_sys_db.py +0 -0
  50. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/README.md +0 -0
  51. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  52. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/__package/main.py +0 -0
  53. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  54. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  55. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  56. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  57. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  58. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  59. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  60. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_tracer.py +0 -0
  61. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_utils.py +0 -0
  62. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_workflow_commands.py +0 -0
  63. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/cli/_github_init.py +0 -0
  64. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/cli/_template_init.py +0 -0
  65. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/cli/cli.py +0 -0
  66. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/dbos-config.schema.json +0 -0
  67. {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/py.typed +0 -0
  68. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/__init__.py +0 -0
  69. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/atexit_no_ctor.py +0 -0
  70. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/atexit_no_launch.py +0 -0
  71. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/classdefs.py +0 -0
  72. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/conftest.py +0 -0
  73. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/more_classdefs.py +0 -0
  74. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/queuedworkflow.py +0 -0
  75. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_admin_server.py +0 -0
  76. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_async.py +0 -0
  77. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_classdecorators.py +0 -0
  78. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_concurrency.py +0 -0
  79. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_config.py +0 -0
  80. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_croniter.py +0 -0
  81. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_dbos.py +0 -0
  82. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_dbwizard.py +0 -0
  83. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_debug.py +0 -0
  84. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_fastapi.py +0 -0
  85. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_fastapi_roles.py +0 -0
  86. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_flask.py +0 -0
  87. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_kafka.py +0 -0
  88. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_outcome.py +0 -0
  89. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_package.py +0 -0
  90. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_queue.py +0 -0
  91. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_scheduler.py +0 -0
  92. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_schema_migration.py +0 -0
  93. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_singleton.py +0 -0
  94. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_spans.py +0 -0
  95. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_sqlalchemy.py +0 -0
  96. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_workflow_cancel.py +0 -0
  97. {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_workflow_cmds.py +0 -0
  98. {dbos-0.24.0a5 → dbos-0.24.0a6}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 0.24.0a5
3
+ Version: 0.24.0a6
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -824,7 +824,9 @@ def decorate_step(
824
824
  stepOutcome = Outcome[R].make(functools.partial(func, *args, **kwargs))
825
825
  if retries_allowed:
826
826
  stepOutcome = stepOutcome.retry(
827
- max_attempts, on_exception, lambda i: DBOSMaxStepRetriesExceeded()
827
+ max_attempts,
828
+ on_exception,
829
+ lambda i: DBOSMaxStepRetriesExceeded(func.__name__, i),
828
830
  )
829
831
 
830
832
  outcome = (
@@ -1,7 +1,7 @@
1
1
  """Errors thrown by DBOS."""
2
2
 
3
3
  from enum import Enum
4
- from typing import Optional
4
+ from typing import Any, Optional
5
5
 
6
6
 
7
7
  class DBOSException(Exception):
@@ -124,12 +124,18 @@ class DBOSNotAuthorizedError(DBOSException):
124
124
  class DBOSMaxStepRetriesExceeded(DBOSException):
125
125
  """Exception raised when a step was retried the maximimum number of times without success."""
126
126
 
127
- def __init__(self) -> None:
127
+ def __init__(self, step_name: str, max_retries: int) -> None:
128
+ self.step_name = step_name
129
+ self.max_retries = max_retries
128
130
  super().__init__(
129
- "Step reached maximum retries.",
131
+ f"Step {step_name} has exceeded its maximum of {max_retries} retries",
130
132
  dbos_error_code=DBOSErrorCode.MaxStepRetriesExceeded.value,
131
133
  )
132
134
 
135
+ def __reduce__(self) -> Any:
136
+ # Tell jsonpickle how to reconstruct this object
137
+ return (self.__class__, (self.step_name, self.max_retries))
138
+
133
139
 
134
140
  class DBOSWorkflowCancelledError(DBOSException):
135
141
  """Exception raised when the workflow has already been cancelled."""
@@ -28,7 +28,7 @@ dependencies = [
28
28
  ]
29
29
  requires-python = ">=3.9"
30
30
  readme = "README.md"
31
- version = "0.24.0a5"
31
+ version = "0.24.0a6"
32
32
 
33
33
  [project.license]
34
34
  text = "MIT"
@@ -8,11 +8,16 @@ import sqlalchemy as sa
8
8
  from psycopg.errors import SerializationFailure
9
9
  from sqlalchemy.exc import InvalidRequestError, OperationalError
10
10
 
11
- # Public API
12
- from dbos import DBOS, GetWorkflowsInput, SetWorkflowID
13
- from dbos._error import DBOSDeadLetterQueueError, DBOSException
11
+ from dbos import DBOS, GetWorkflowsInput, Queue, SetWorkflowID
12
+ from dbos._error import (
13
+ DBOSDeadLetterQueueError,
14
+ DBOSException,
15
+ DBOSMaxStepRetriesExceeded,
16
+ )
14
17
  from dbos._sys_db import WorkflowStatusString
15
18
 
19
+ from .conftest import queue_entries_are_cleaned_up
20
+
16
21
 
17
22
  def test_transaction_errors(dbos: DBOS) -> None:
18
23
  retry_counter: int = 0
@@ -258,3 +263,64 @@ def test_wfstatus_invalid(dbos: DBOS) -> None:
258
263
  with SetWorkflowID(wfuuid):
259
264
  non_deterministic_worklow()
260
265
  assert "Hint: Check if your workflow is deterministic." in str(exc_info.value)
266
+
267
+
268
+ def test_step_retries(dbos: DBOS) -> None:
269
+ step_counter = 0
270
+
271
+ queue = Queue("test-queue")
272
+ max_attempts = 2
273
+
274
+ @DBOS.step(retries_allowed=True, interval_seconds=0, max_attempts=max_attempts)
275
+ def failing_step() -> None:
276
+ nonlocal step_counter
277
+ step_counter += 1
278
+ raise Exception("fail")
279
+
280
+ @DBOS.workflow()
281
+ def failing_workflow() -> None:
282
+ failing_step()
283
+
284
+ @DBOS.workflow()
285
+ def enqueue_failing_step() -> None:
286
+ queue.enqueue(failing_step).get_result()
287
+
288
+ error_message = f"Step {failing_step.__name__} has exceeded its maximum of {max_attempts} retries"
289
+
290
+ # Test calling the step directly
291
+ with pytest.raises(DBOSMaxStepRetriesExceeded) as excinfo:
292
+ failing_step()
293
+ assert error_message in str(excinfo.value)
294
+ assert step_counter == max_attempts
295
+
296
+ # Test calling the workflow
297
+ step_counter = 0
298
+ with pytest.raises(DBOSMaxStepRetriesExceeded) as excinfo:
299
+ failing_workflow()
300
+ assert error_message in str(excinfo.value)
301
+ assert step_counter == max_attempts
302
+
303
+ # Test enqueueing the step
304
+ step_counter = 0
305
+ handle = queue.enqueue(failing_step)
306
+ with pytest.raises(DBOSMaxStepRetriesExceeded) as excinfo:
307
+ handle.get_result()
308
+ assert error_message in str(excinfo.value)
309
+ assert step_counter == max_attempts
310
+
311
+ # Test enqueuing the workflow
312
+ step_counter = 0
313
+ handle = queue.enqueue(failing_workflow)
314
+ with pytest.raises(DBOSMaxStepRetriesExceeded) as excinfo:
315
+ handle.get_result()
316
+ assert error_message in str(excinfo.value)
317
+ assert step_counter == max_attempts
318
+
319
+ # Test enqueuing the step from a workflow
320
+ step_counter = 0
321
+ with pytest.raises(DBOSMaxStepRetriesExceeded) as excinfo:
322
+ enqueue_failing_step()
323
+ assert error_message in str(excinfo.value)
324
+ assert step_counter == max_attempts
325
+
326
+ assert queue_entries_are_cleaned_up(dbos)
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