dbos 0.23.0a14__tar.gz → 0.24.0a3__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 (97) hide show
  1. {dbos-0.23.0a14 → dbos-0.24.0a3}/PKG-INFO +1 -1
  2. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_conductor/conductor.py +22 -12
  3. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_debug.py +7 -1
  4. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_scheduler.py +5 -2
  5. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_sys_db.py +5 -1
  6. {dbos-0.23.0a14 → dbos-0.24.0a3}/pyproject.toml +1 -1
  7. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_debug.py +2 -2
  8. {dbos-0.23.0a14 → dbos-0.24.0a3}/LICENSE +0 -0
  9. {dbos-0.23.0a14 → dbos-0.24.0a3}/README.md +0 -0
  10. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/__init__.py +0 -0
  11. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/__main__.py +0 -0
  12. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_admin_server.py +0 -0
  13. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_app_db.py +0 -0
  14. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_classproperty.py +0 -0
  15. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_cloudutils/authentication.py +0 -0
  16. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_cloudutils/cloudutils.py +0 -0
  17. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_cloudutils/databases.py +0 -0
  18. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_conductor/protocol.py +0 -0
  19. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_context.py +0 -0
  20. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_core.py +0 -0
  21. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_croniter.py +0 -0
  22. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_db_wizard.py +0 -0
  23. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_dbos.py +0 -0
  24. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_dbos_config.py +0 -0
  25. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_error.py +0 -0
  26. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_fastapi.py +0 -0
  27. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_flask.py +0 -0
  28. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_kafka.py +0 -0
  29. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_kafka_message.py +0 -0
  30. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_logger.py +0 -0
  31. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/env.py +0 -0
  32. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/script.py.mako +0 -0
  33. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  34. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  35. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  36. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  37. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  38. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  39. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  40. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_outcome.py +0 -0
  41. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_queue.py +0 -0
  42. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_recovery.py +0 -0
  43. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_registrations.py +0 -0
  44. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_request.py +0 -0
  45. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_roles.py +0 -0
  46. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_schemas/__init__.py +0 -0
  47. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_schemas/application_database.py +0 -0
  48. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_schemas/system_database.py +0 -0
  49. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_serialization.py +0 -0
  50. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/README.md +0 -0
  51. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  52. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/__package/main.py +0 -0
  53. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  54. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  55. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  56. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  57. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  58. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  59. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  60. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_tracer.py +0 -0
  61. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_utils.py +0 -0
  62. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/_workflow_commands.py +0 -0
  63. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/cli/_github_init.py +0 -0
  64. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/cli/_template_init.py +0 -0
  65. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/cli/cli.py +0 -0
  66. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/dbos-config.schema.json +0 -0
  67. {dbos-0.23.0a14 → dbos-0.24.0a3}/dbos/py.typed +0 -0
  68. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/__init__.py +0 -0
  69. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/atexit_no_ctor.py +0 -0
  70. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/atexit_no_launch.py +0 -0
  71. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/classdefs.py +0 -0
  72. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/conftest.py +0 -0
  73. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/more_classdefs.py +0 -0
  74. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/queuedworkflow.py +0 -0
  75. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_admin_server.py +0 -0
  76. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_async.py +0 -0
  77. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_classdecorators.py +0 -0
  78. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_concurrency.py +0 -0
  79. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_config.py +0 -0
  80. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_croniter.py +0 -0
  81. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_dbos.py +0 -0
  82. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_failures.py +0 -0
  83. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_fastapi.py +0 -0
  84. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_fastapi_roles.py +0 -0
  85. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_flask.py +0 -0
  86. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_kafka.py +0 -0
  87. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_outcome.py +0 -0
  88. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_package.py +0 -0
  89. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_queue.py +0 -0
  90. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_scheduler.py +0 -0
  91. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_schema_migration.py +0 -0
  92. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_singleton.py +0 -0
  93. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_spans.py +0 -0
  94. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_sqlalchemy.py +0 -0
  95. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_workflow_cancel.py +0 -0
  96. {dbos-0.23.0a14 → dbos-0.24.0a3}/tests/test_workflow_cmds.py +0 -0
  97. {dbos-0.23.0a14 → dbos-0.24.0a3}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 0.23.0a14
3
+ Version: 0.24.0a3
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -3,7 +3,7 @@ import time
3
3
  import traceback
4
4
  from typing import TYPE_CHECKING, Optional
5
5
 
6
- from websockets import ConnectionClosed, ConnectionClosedOK
6
+ from websockets import ConnectionClosed, ConnectionClosedOK, InvalidStatus
7
7
  from websockets.sync.client import connect
8
8
  from websockets.sync.connection import Connection
9
9
 
@@ -39,12 +39,12 @@ class ConductorWebsocket(threading.Thread):
39
39
  message = websocket.recv()
40
40
  if not isinstance(message, str):
41
41
  self.dbos.logger.warning(
42
- "Receieved unexpected non-str message"
42
+ "Received unexpected non-str message"
43
43
  )
44
44
  continue
45
45
  base_message = p.BaseMessage.from_json(message)
46
- type = base_message.type
47
- if type == p.MessageType.EXECUTOR_INFO:
46
+ msg_type = base_message.type
47
+ if msg_type == p.MessageType.EXECUTOR_INFO:
48
48
  info_response = p.ExecutorInfoResponse(
49
49
  type=p.MessageType.EXECUTOR_INFO,
50
50
  request_id=base_message.request_id,
@@ -53,7 +53,7 @@ class ConductorWebsocket(threading.Thread):
53
53
  )
54
54
  websocket.send(info_response.to_json())
55
55
  self.dbos.logger.info("Connected to DBOS conductor")
56
- elif type == p.MessageType.RECOVERY:
56
+ elif msg_type == p.MessageType.RECOVERY:
57
57
  recovery_message = p.RecoveryRequest.from_json(message)
58
58
  success = True
59
59
  try:
@@ -71,7 +71,7 @@ class ConductorWebsocket(threading.Thread):
71
71
  success=success,
72
72
  )
73
73
  websocket.send(recovery_response.to_json())
74
- elif type == p.MessageType.CANCEL:
74
+ elif msg_type == p.MessageType.CANCEL:
75
75
  cancel_message = p.CancelRequest.from_json(message)
76
76
  success = True
77
77
  try:
@@ -87,7 +87,7 @@ class ConductorWebsocket(threading.Thread):
87
87
  success=success,
88
88
  )
89
89
  websocket.send(cancel_response.to_json())
90
- elif type == p.MessageType.RESUME:
90
+ elif msg_type == p.MessageType.RESUME:
91
91
  resume_message = p.ResumeRequest.from_json(message)
92
92
  success = True
93
93
  try:
@@ -103,7 +103,7 @@ class ConductorWebsocket(threading.Thread):
103
103
  success=success,
104
104
  )
105
105
  websocket.send(resume_response.to_json())
106
- elif type == p.MessageType.RESTART:
106
+ elif msg_type == p.MessageType.RESTART:
107
107
  restart_message = p.RestartRequest.from_json(message)
108
108
  success = True
109
109
  try:
@@ -119,7 +119,7 @@ class ConductorWebsocket(threading.Thread):
119
119
  success=success,
120
120
  )
121
121
  websocket.send(restart_response.to_json())
122
- elif type == p.MessageType.LIST_WORKFLOWS:
122
+ elif msg_type == p.MessageType.LIST_WORKFLOWS:
123
123
  list_workflows_message = p.ListWorkflowsRequest.from_json(
124
124
  message
125
125
  )
@@ -147,7 +147,7 @@ class ConductorWebsocket(threading.Thread):
147
147
  ],
148
148
  )
149
149
  websocket.send(list_workflows_response.to_json())
150
- elif type == p.MessageType.LIST_QUEUED_WORKFLOWS:
150
+ elif msg_type == p.MessageType.LIST_QUEUED_WORKFLOWS:
151
151
  list_queued_workflows_message = (
152
152
  p.ListQueuedWorkflowsRequest.from_json(message)
153
153
  )
@@ -175,7 +175,7 @@ class ConductorWebsocket(threading.Thread):
175
175
  )
176
176
  )
177
177
  websocket.send(list_queued_workflows_response.to_json())
178
- elif type == p.MessageType.GET_WORKFLOW:
178
+ elif msg_type == p.MessageType.GET_WORKFLOW:
179
179
  get_workflow_message = p.GetWorkflowRequest.from_json(
180
180
  message
181
181
  )
@@ -195,7 +195,9 @@ class ConductorWebsocket(threading.Thread):
195
195
  )
196
196
  websocket.send(get_workflow_response.to_json())
197
197
  else:
198
- self.dbos.logger.warning(f"Unexpected message type: {type}")
198
+ self.dbos.logger.warning(
199
+ f"Unexpected message type: {msg_type}"
200
+ )
199
201
  except ConnectionClosedOK:
200
202
  self.dbos.logger.info("Conductor connection terminated")
201
203
  break
@@ -205,6 +207,14 @@ class ConductorWebsocket(threading.Thread):
205
207
  )
206
208
  time.sleep(1)
207
209
  continue
210
+ except InvalidStatus as e:
211
+ # This happens when it cannot open a connection to the conductor. E.g., the conductor rejects the request
212
+ json_data = e.response.body.decode("utf-8")
213
+ self.dbos.logger.error(
214
+ f"Failed to connect to conductor. Retrying: {str(e) }. Details: {json_data}"
215
+ )
216
+ time.sleep(1)
217
+ continue
208
218
  except Exception as e:
209
219
  self.dbos.logger.error(
210
220
  f"Unexpected exception in connection to conductor. Reconnecting: {e}"
@@ -1,8 +1,11 @@
1
1
  import re
2
2
  import runpy
3
3
  import sys
4
+ from pathlib import Path
4
5
  from typing import Union
5
6
 
7
+ from fastapi_cli.discover import get_module_data_from_path
8
+
6
9
  from dbos import DBOS
7
10
 
8
11
 
@@ -33,7 +36,10 @@ def debug_workflow(workflow_id: str, entrypoint: Union[str, PythonModule]) -> No
33
36
  def parse_start_command(command: str) -> Union[str, PythonModule]:
34
37
  match = re.match(r"fastapi\s+run\s+(\.?[\w/]+\.py)", command)
35
38
  if match:
36
- return match.group(1)
39
+ # Mirror the logic in fastapi's run command by converting the path argument to a module
40
+ mod_data = get_module_data_from_path(Path(match.group(1)))
41
+ sys.path.insert(0, str(mod_data.extra_sys_path))
42
+ return PythonModule(mod_data.module_import_str)
37
43
  match = re.match(r"python3?\s+(\.?[\w/]+\.py)", command)
38
44
  if match:
39
45
  return match.group(1)
@@ -1,4 +1,5 @@
1
1
  import threading
2
+ import traceback
2
3
  from datetime import datetime, timezone
3
4
  from typing import TYPE_CHECKING, Callable
4
5
 
@@ -33,8 +34,10 @@ def scheduler_loop(
33
34
  with SetWorkflowID(f"sched-{func.__qualname__}-{nextExecTime.isoformat()}"):
34
35
  try:
35
36
  scheduler_queue.enqueue(func, nextExecTime, datetime.now(timezone.utc))
36
- except Exception as e:
37
- dbos_logger.warning(f"Error scheduling workflow: ", e)
37
+ except Exception:
38
+ dbos_logger.warning(
39
+ f"Exception encountered in scheduler thread: {traceback.format_exc()})"
40
+ )
38
41
 
39
42
 
40
43
  def scheduled(
@@ -202,7 +202,11 @@ class SystemDatabase:
202
202
 
203
203
  # Create a connection pool for the system database
204
204
  self.engine = sa.create_engine(
205
- system_db_url, pool_size=20, max_overflow=5, pool_timeout=30
205
+ system_db_url,
206
+ pool_size=20,
207
+ max_overflow=5,
208
+ pool_timeout=30,
209
+ connect_args={"connect_timeout": 10},
206
210
  )
207
211
 
208
212
  # Run a schema migration for the system database
@@ -28,7 +28,7 @@ dependencies = [
28
28
  ]
29
29
  requires-python = ">=3.9"
30
30
  readme = "README.md"
31
- version = "0.23.0a14"
31
+ version = "0.24.0a3"
32
32
 
33
33
  [project.license]
34
34
  text = "MIT"
@@ -11,9 +11,9 @@ from dbos._schemas.system_database import SystemSchema
11
11
 
12
12
  def test_parse_fast_api_command() -> None:
13
13
  command = "fastapi run app/main.py"
14
- expected = "app/main.py"
15
14
  actual = parse_start_command(command)
16
- assert actual == expected
15
+ assert isinstance(actual, PythonModule)
16
+ assert actual.module_name == "main"
17
17
 
18
18
 
19
19
  def test_parse_python_command() -> None:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes