dbos 1.2.0a2__tar.gz → 1.2.0a5__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.
Files changed (107) hide show
  1. {dbos-1.2.0a2 → dbos-1.2.0a5}/PKG-INFO +1 -1
  2. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_client.py +2 -1
  3. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_core.py +11 -3
  4. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_dbos.py +0 -2
  5. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_dbos_config.py +1 -23
  6. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_queue.py +6 -7
  7. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_sys_db.py +169 -115
  8. dbos-1.2.0a5/dbos/_utils.py +50 -0
  9. {dbos-1.2.0a2 → dbos-1.2.0a5}/pyproject.toml +1 -1
  10. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/conftest.py +3 -20
  11. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_client.py +6 -0
  12. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_config.py +10 -38
  13. dbos-1.2.0a2/dbos/_utils.py +0 -17
  14. {dbos-1.2.0a2 → dbos-1.2.0a5}/LICENSE +0 -0
  15. {dbos-1.2.0a2 → dbos-1.2.0a5}/README.md +0 -0
  16. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/__init__.py +0 -0
  17. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/__main__.py +0 -0
  18. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_admin_server.py +0 -0
  19. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_app_db.py +0 -0
  20. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_classproperty.py +0 -0
  21. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_conductor/conductor.py +0 -0
  22. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_conductor/protocol.py +0 -0
  23. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_context.py +0 -0
  24. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_croniter.py +0 -0
  25. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_debug.py +0 -0
  26. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_docker_pg_helper.py +0 -0
  27. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_error.py +0 -0
  28. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_event_loop.py +0 -0
  29. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_fastapi.py +0 -0
  30. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_flask.py +0 -0
  31. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_kafka.py +0 -0
  32. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_kafka_message.py +0 -0
  33. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_logger.py +0 -0
  34. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/env.py +0 -0
  35. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/script.py.mako +0 -0
  36. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  37. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/27ac6900c6ad_add_queue_dedup.py +0 -0
  38. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  39. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  40. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/83f3732ae8e7_workflow_timeout.py +0 -0
  41. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/933e86bdac6a_add_queue_priority.py +0 -0
  42. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  43. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  44. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  45. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  46. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_migrations/versions/f4b9b32ba814_functionname_childid_op_outputs.py +0 -0
  47. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_outcome.py +0 -0
  48. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_recovery.py +0 -0
  49. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_registrations.py +0 -0
  50. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_roles.py +0 -0
  51. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_scheduler.py +0 -0
  52. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_schemas/__init__.py +0 -0
  53. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_schemas/application_database.py +0 -0
  54. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_schemas/system_database.py +0 -0
  55. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_serialization.py +0 -0
  56. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/README.md +0 -0
  57. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  58. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/__package/main.py.dbos +0 -0
  59. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  60. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  61. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  62. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  63. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  64. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  65. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  66. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_tracer.py +0 -0
  67. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/_workflow_commands.py +0 -0
  68. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/cli/_github_init.py +0 -0
  69. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/cli/_template_init.py +0 -0
  70. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/cli/cli.py +0 -0
  71. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/dbos-config.schema.json +0 -0
  72. {dbos-1.2.0a2 → dbos-1.2.0a5}/dbos/py.typed +0 -0
  73. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/__init__.py +0 -0
  74. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/atexit_no_ctor.py +0 -0
  75. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/atexit_no_launch.py +0 -0
  76. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/classdefs.py +0 -0
  77. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/client_collateral.py +0 -0
  78. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/client_worker.py +0 -0
  79. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/dupname_classdefs1.py +0 -0
  80. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/dupname_classdefsa.py +0 -0
  81. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/more_classdefs.py +0 -0
  82. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/queuedworkflow.py +0 -0
  83. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_admin_server.py +0 -0
  84. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_async.py +0 -0
  85. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_classdecorators.py +0 -0
  86. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_cli.py +0 -0
  87. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_concurrency.py +0 -0
  88. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_croniter.py +0 -0
  89. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_dbos.py +0 -0
  90. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_debug.py +0 -0
  91. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_docker_secrets.py +0 -0
  92. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_failures.py +0 -0
  93. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_fastapi.py +0 -0
  94. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_fastapi_roles.py +0 -0
  95. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_flask.py +0 -0
  96. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_kafka.py +0 -0
  97. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_outcome.py +0 -0
  98. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_package.py +0 -0
  99. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_queue.py +0 -0
  100. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_scheduler.py +0 -0
  101. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_schema_migration.py +0 -0
  102. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_singleton.py +0 -0
  103. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_spans.py +0 -0
  104. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_sqlalchemy.py +0 -0
  105. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_workflow_introspection.py +0 -0
  106. {dbos-1.2.0a2 → dbos-1.2.0a5}/tests/test_workflow_management.py +0 -0
  107. {dbos-1.2.0a2 → dbos-1.2.0a5}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 1.2.0a2
3
+ Version: 1.2.0a5
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -109,6 +109,7 @@ class DBOSClient:
109
109
  },
110
110
  sys_db_name=system_database,
111
111
  )
112
+ self._sys_db.check_connection()
112
113
  self._app_db = ApplicationDatabase(
113
114
  database_url=database_url,
114
115
  engine_kwargs={
@@ -231,7 +232,7 @@ class DBOSClient:
231
232
  "workflow_deadline_epoch_ms": None,
232
233
  }
233
234
  with self._sys_db.engine.begin() as conn:
234
- self._sys_db.insert_workflow_status(
235
+ self._sys_db._insert_workflow_status(
235
236
  status, conn, max_recovery_attempts=None
236
237
  )
237
238
  self._sys_db.send(status["workflow_uuid"], 0, destination_id, message, topic)
@@ -20,8 +20,10 @@ from typing import (
20
20
  cast,
21
21
  )
22
22
 
23
+ import psycopg
24
+
23
25
  from dbos._outcome import Immediate, NoResult, Outcome, Pending
24
- from dbos._utils import GlobalParams
26
+ from dbos._utils import GlobalParams, retriable_postgres_exception
25
27
 
26
28
  from ._app_db import ApplicationDatabase, TransactionResultInternal
27
29
 
@@ -931,12 +933,18 @@ def decorate_transaction(
931
933
  )
932
934
  break
933
935
  except DBAPIError as dbapi_error:
934
- if dbapi_error.orig.sqlstate == "40001": # type: ignore
936
+ driver_error = cast(
937
+ Optional[psycopg.OperationalError], dbapi_error.orig
938
+ )
939
+ if retriable_postgres_exception(dbapi_error) or (
940
+ driver_error is not None
941
+ and driver_error.sqlstate == "40001"
942
+ ):
935
943
  # Retry on serialization failure
936
944
  span = ctx.get_current_span()
937
945
  if span:
938
946
  span.add_event(
939
- "Transaction Serialization Failure",
947
+ "Transaction Failure",
940
948
  {"retry_wait_seconds": retry_wait_seconds},
941
949
  )
942
950
  time.sleep(retry_wait_seconds)
@@ -90,7 +90,6 @@ from ._context import (
90
90
  from ._dbos_config import (
91
91
  ConfigFile,
92
92
  DBOSConfig,
93
- check_config_consistency,
94
93
  overwrite_config,
95
94
  process_config,
96
95
  set_env_vars,
@@ -324,7 +323,6 @@ class DBOS:
324
323
  unvalidated_config = translate_dbos_config_to_config_file(config)
325
324
  if os.environ.get("DBOS__CLOUD") == "true":
326
325
  unvalidated_config = overwrite_config(unvalidated_config)
327
- check_config_consistency(name=unvalidated_config["name"])
328
326
 
329
327
  if unvalidated_config is not None:
330
328
  self._config: ConfigFile = process_config(data=unvalidated_config)
@@ -407,6 +407,7 @@ def configure_db_engine_parameters(
407
407
  "pool_timeout": 30,
408
408
  "max_overflow": 0,
409
409
  "pool_size": 20,
410
+ "pool_pre_ping": True,
410
411
  }
411
412
  # If user-provided kwargs are present, use them instead
412
413
  user_kwargs = data.get("db_engine_kwargs")
@@ -529,26 +530,3 @@ def overwrite_config(provided_config: ConfigFile) -> ConfigFile:
529
530
  del provided_config["env"]
530
531
 
531
532
  return provided_config
532
-
533
-
534
- def check_config_consistency(
535
- *,
536
- name: str,
537
- config_file_path: str = DBOS_CONFIG_PATH,
538
- ) -> None:
539
- # First load the config file and check whether it is present
540
- try:
541
- config = load_config(config_file_path, silent=True, run_process_config=False)
542
- except FileNotFoundError:
543
- dbos_logger.debug(
544
- f"No configuration file {config_file_path} found. Skipping consistency check with provided config."
545
- )
546
- return
547
- except Exception as e:
548
- raise e
549
-
550
- # Check the name
551
- if name != config["name"]:
552
- raise DBOSInitializationError(
553
- f"Provided app name '{name}' does not match the app name '{config['name']}' in {config_file_path}."
554
- )
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any, Callable, Coroutine, Optional, TypedDict
5
5
  from psycopg import errors
6
6
  from sqlalchemy.exc import OperationalError
7
7
 
8
+ from dbos._logger import dbos_logger
8
9
  from dbos._utils import GlobalParams
9
10
 
10
11
  from ._core import P, R, execute_workflow_by_id, start_workflow, start_workflow_async
@@ -56,6 +57,8 @@ class Queue:
56
57
  from ._dbos import _get_or_create_dbos_registry
57
58
 
58
59
  registry = _get_or_create_dbos_registry()
60
+ if self.name in registry.queue_info_map:
61
+ dbos_logger.warning(f"Queue {name} has already been declared")
59
62
  registry.queue_info_map[self.name] = self
60
63
 
61
64
  def enqueue(
@@ -95,12 +98,8 @@ def queue_thread(stop_event: threading.Event, dbos: "DBOS") -> None:
95
98
  if not isinstance(
96
99
  e.orig, (errors.SerializationFailure, errors.LockNotAvailable)
97
100
  ):
98
- dbos.logger.warning(
99
- f"Exception encountered in queue thread: {traceback.format_exc()}"
100
- )
101
- except Exception:
101
+ dbos.logger.warning(f"Exception encountered in queue thread: {e}")
102
+ except Exception as e:
102
103
  if not stop_event.is_set():
103
104
  # Only print the error if the thread is not stopping
104
- dbos.logger.warning(
105
- f"Exception encountered in queue thread: {traceback.format_exc()}"
106
- )
105
+ dbos.logger.warning(f"Exception encountered in queue thread: {e}")