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.
- {dbos-0.24.0a5 → dbos-0.24.0a6}/PKG-INFO +1 -1
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_core.py +3 -1
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_error.py +9 -3
- {dbos-0.24.0a5 → dbos-0.24.0a6}/pyproject.toml +1 -1
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_failures.py +69 -3
- {dbos-0.24.0a5 → dbos-0.24.0a6}/LICENSE +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/README.md +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/__init__.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/__main__.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_admin_server.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_app_db.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_classproperty.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_cloudutils/authentication.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_cloudutils/cloudutils.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_cloudutils/databases.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_conductor/conductor.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_conductor/protocol.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_context.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_croniter.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_db_wizard.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_dbos.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_dbos_config.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_debug.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_fastapi.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_flask.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_kafka.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_kafka_message.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_logger.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/env.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/script.py.mako +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_outcome.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_queue.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_recovery.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_registrations.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_request.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_roles.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_scheduler.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_schemas/__init__.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_schemas/application_database.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_schemas/system_database.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_serialization.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_sys_db.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/README.md +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/__package/main.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_tracer.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_utils.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/_workflow_commands.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/cli/_github_init.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/cli/_template_init.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/cli/cli.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/dbos-config.schema.json +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/dbos/py.typed +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/__init__.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/atexit_no_ctor.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/atexit_no_launch.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/classdefs.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/conftest.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/more_classdefs.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/queuedworkflow.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_admin_server.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_async.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_classdecorators.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_concurrency.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_config.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_croniter.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_dbos.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_dbwizard.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_debug.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_fastapi.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_fastapi_roles.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_flask.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_kafka.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_outcome.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_package.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_queue.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_scheduler.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_schema_migration.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_singleton.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_spans.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_sqlalchemy.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_workflow_cancel.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/tests/test_workflow_cmds.py +0 -0
- {dbos-0.24.0a5 → dbos-0.24.0a6}/version/__init__.py +0 -0
|
@@ -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,
|
|
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
|
|
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."""
|
|
@@ -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
|
-
|
|
12
|
-
from dbos import
|
|
13
|
-
|
|
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
|
{dbos-0.24.0a5 → dbos-0.24.0a6}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|