dbos 0.11.0a3__py3-none-any.whl → 0.12.0__py3-none-any.whl
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/__init__.py +7 -7
- dbos/{admin_sever.py → _admin_sever.py} +20 -11
- dbos/{application_database.py → _app_db.py} +4 -5
- dbos/{decorators.py → _classproperty.py} +3 -3
- dbos/{context.py → _context.py} +26 -26
- dbos/{core.py → _core.py} +121 -107
- dbos/{dbos.py → _dbos.py} +57 -59
- dbos/{dbos_config.py → _dbos_config.py} +9 -9
- dbos/{fastapi.py → _fastapi.py} +10 -11
- dbos/{flask.py → _flask.py} +6 -7
- dbos/{kafka.py → _kafka.py} +18 -18
- dbos/{logger.py → _logger.py} +13 -13
- dbos/{queue.py → _queue.py} +7 -7
- dbos/{recovery.py → _recovery.py} +8 -8
- dbos/{roles.py → _roles.py} +5 -5
- dbos/{scheduler/scheduler.py → _scheduler.py} +17 -7
- dbos/{utils.py → _serialization.py} +4 -4
- dbos/{system_database.py → _sys_db.py} +42 -37
- dbos/{tracer.py → _tracer.py} +2 -2
- dbos/cli.py +21 -21
- {dbos-0.11.0a3.dist-info → dbos-0.12.0.dist-info}/METADATA +2 -2
- dbos-0.12.0.dist-info/RECORD +54 -0
- {dbos-0.11.0a3.dist-info → dbos-0.12.0.dist-info}/WHEEL +1 -1
- dbos-0.11.0a3.dist-info/RECORD +0 -54
- /dbos/{scheduler/croniter.py → _croniter.py} +0 -0
- /dbos/{error.py → _error.py} +0 -0
- /dbos/{kafka_message.py → _kafka_message.py} +0 -0
- /dbos/{migrations → _migrations}/env.py +0 -0
- /dbos/{migrations → _migrations}/script.py.mako +0 -0
- /dbos/{migrations → _migrations}/versions/50f3227f0b4b_fix_job_queue.py +0 -0
- /dbos/{migrations → _migrations}/versions/5c361fc04708_added_system_tables.py +0 -0
- /dbos/{migrations → _migrations}/versions/a3b18ad34abe_added_triggers.py +0 -0
- /dbos/{migrations → _migrations}/versions/d76646551a6b_job_queue_limiter.py +0 -0
- /dbos/{migrations → _migrations}/versions/d76646551a6c_workflow_queue.py +0 -0
- /dbos/{migrations → _migrations}/versions/eab0cc1d9a14_job_queue.py +0 -0
- /dbos/{registrations.py → _registrations.py} +0 -0
- /dbos/{request.py → _request.py} +0 -0
- /dbos/{schemas → _schemas}/__init__.py +0 -0
- /dbos/{schemas → _schemas}/application_database.py +0 -0
- /dbos/{schemas → _schemas}/system_database.py +0 -0
- /dbos/{templates → _templates}/hello/README.md +0 -0
- /dbos/{templates → _templates}/hello/__package/__init__.py +0 -0
- /dbos/{templates → _templates}/hello/__package/main.py +0 -0
- /dbos/{templates → _templates}/hello/__package/schema.py +0 -0
- /dbos/{templates → _templates}/hello/alembic.ini +0 -0
- /dbos/{templates → _templates}/hello/dbos-config.yaml.dbos +0 -0
- /dbos/{templates → _templates}/hello/migrations/env.py.dbos +0 -0
- /dbos/{templates → _templates}/hello/migrations/script.py.mako +0 -0
- /dbos/{templates → _templates}/hello/migrations/versions/2024_07_31_180642_init.py +0 -0
- /dbos/{templates → _templates}/hello/start_postgres_docker.py +0 -0
- {dbos-0.11.0a3.dist-info → dbos-0.12.0.dist-info}/entry_points.txt +0 -0
- {dbos-0.11.0a3.dist-info → dbos-0.12.0.dist-info}/licenses/LICENSE +0 -0
dbos/__init__.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from . import
|
|
2
|
-
from .
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
5
|
-
from .
|
|
6
|
-
from .
|
|
7
|
-
from .
|
|
1
|
+
from . import _error as error
|
|
2
|
+
from ._context import DBOSContextEnsure, DBOSContextSetAuth, SetWorkflowID
|
|
3
|
+
from ._dbos import DBOS, DBOSConfiguredInstance, WorkflowHandle, WorkflowStatus
|
|
4
|
+
from ._dbos_config import ConfigFile, get_dbos_database_url, load_config
|
|
5
|
+
from ._kafka_message import KafkaMessage
|
|
6
|
+
from ._queue import Queue
|
|
7
|
+
from ._sys_db import GetWorkflowsInput, WorkflowStatusString
|
|
8
8
|
|
|
9
9
|
__all__ = [
|
|
10
10
|
"ConfigFile",
|
|
@@ -8,16 +8,16 @@ from typing import TYPE_CHECKING, Any, List, TypedDict
|
|
|
8
8
|
|
|
9
9
|
import psutil
|
|
10
10
|
|
|
11
|
-
from
|
|
12
|
-
|
|
13
|
-
from .logger import dbos_logger
|
|
11
|
+
from ._logger import dbos_logger
|
|
12
|
+
from ._recovery import recover_pending_workflows
|
|
14
13
|
|
|
15
14
|
if TYPE_CHECKING:
|
|
16
|
-
from .
|
|
15
|
+
from ._dbos import DBOS
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
_health_check_path = "/dbos-healthz"
|
|
18
|
+
_workflow_recovery_path = "/dbos-workflow-recovery"
|
|
19
|
+
_perf_path = "/dbos-perf"
|
|
20
|
+
_deactivate_path = "/deactivate"
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class AdminServer:
|
|
@@ -51,11 +51,11 @@ class AdminRequestHandler(BaseHTTPRequestHandler):
|
|
|
51
51
|
self._end_headers()
|
|
52
52
|
|
|
53
53
|
def do_GET(self) -> None:
|
|
54
|
-
if self.path ==
|
|
54
|
+
if self.path == _health_check_path:
|
|
55
55
|
self.send_response(200)
|
|
56
56
|
self._end_headers()
|
|
57
57
|
self.wfile.write("healthy".encode("utf-8"))
|
|
58
|
-
elif self.path ==
|
|
58
|
+
elif self.path == _perf_path:
|
|
59
59
|
# Compares system CPU times elapsed since last call or module import, returning immediately (non blocking).
|
|
60
60
|
cpu_percent = psutil.cpu_percent(interval=None) / 100.0
|
|
61
61
|
perf_util: PerfUtilization = {
|
|
@@ -66,6 +66,15 @@ class AdminRequestHandler(BaseHTTPRequestHandler):
|
|
|
66
66
|
self.send_response(200)
|
|
67
67
|
self._end_headers()
|
|
68
68
|
self.wfile.write(json.dumps(perf_util).encode("utf-8"))
|
|
69
|
+
elif self.path == _deactivate_path:
|
|
70
|
+
dbos_logger.info("Deactivating DBOS")
|
|
71
|
+
# Stop all scheduled workflows, queues, and kafka loops
|
|
72
|
+
for event in self.dbos.stop_events:
|
|
73
|
+
event.set()
|
|
74
|
+
|
|
75
|
+
self.send_response(200)
|
|
76
|
+
self._end_headers()
|
|
77
|
+
self.wfile.write("deactivated".encode("utf-8"))
|
|
69
78
|
else:
|
|
70
79
|
self.send_response(404)
|
|
71
80
|
self._end_headers()
|
|
@@ -76,10 +85,10 @@ class AdminRequestHandler(BaseHTTPRequestHandler):
|
|
|
76
85
|
) # <--- Gets the size of data
|
|
77
86
|
post_data = self.rfile.read(content_length) # <--- Gets the data itself
|
|
78
87
|
|
|
79
|
-
if self.path ==
|
|
88
|
+
if self.path == _workflow_recovery_path:
|
|
80
89
|
executor_ids: List[str] = json.loads(post_data.decode("utf-8"))
|
|
81
90
|
dbos_logger.info("Recovering workflows for executors: %s", executor_ids)
|
|
82
|
-
workflow_handles =
|
|
91
|
+
workflow_handles = recover_pending_workflows(self.dbos, executor_ids)
|
|
83
92
|
workflow_ids = [handle.workflow_id for handle in workflow_handles]
|
|
84
93
|
self.send_response(200)
|
|
85
94
|
self._end_headers()
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
from typing import Optional, TypedDict
|
|
1
|
+
from typing import Optional, TypedDict
|
|
2
2
|
|
|
3
3
|
import sqlalchemy as sa
|
|
4
4
|
import sqlalchemy.dialects.postgresql as pg
|
|
5
5
|
from sqlalchemy.exc import DBAPIError
|
|
6
6
|
from sqlalchemy.orm import Session, sessionmaker
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
|
|
11
|
-
from .dbos_config import ConfigFile
|
|
8
|
+
from ._dbos_config import ConfigFile
|
|
9
|
+
from ._error import DBOSWorkflowConflictIDError
|
|
10
|
+
from ._schemas.application_database import ApplicationSchema
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class TransactionResultInternal(TypedDict):
|
|
@@ -3,7 +3,7 @@ from typing import Any, Callable, Generic, Optional, TypeVar
|
|
|
3
3
|
G = TypeVar("G") # A generic type for ClassPropertyDescriptor getters
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class ClassPropertyDescriptor(Generic[G]):
|
|
7
7
|
def __init__(self, fget: Callable[..., G]) -> None:
|
|
8
8
|
self.fget = fget
|
|
9
9
|
|
|
@@ -15,5 +15,5 @@ class _ClassPropertyDescriptor(Generic[G]):
|
|
|
15
15
|
return self.fget(objtype)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def classproperty(func: Callable[..., G]) ->
|
|
19
|
-
return
|
|
18
|
+
def classproperty(func: Callable[..., G]) -> ClassPropertyDescriptor[G]:
|
|
19
|
+
return ClassPropertyDescriptor(func)
|
dbos/{context.py → _context.py}
RENAMED
|
@@ -7,14 +7,14 @@ from contextlib import AbstractContextManager
|
|
|
7
7
|
from contextvars import ContextVar
|
|
8
8
|
from enum import Enum
|
|
9
9
|
from types import TracebackType
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import List, Literal, Optional, Type, TypedDict
|
|
11
11
|
|
|
12
12
|
from opentelemetry.trace import Span, Status, StatusCode
|
|
13
13
|
from sqlalchemy.orm import Session
|
|
14
14
|
|
|
15
|
-
from .
|
|
16
|
-
from .
|
|
17
|
-
from .
|
|
15
|
+
from ._logger import dbos_logger
|
|
16
|
+
from ._request import Request
|
|
17
|
+
from ._tracer import dbos_tracer
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
# These are used to tag OTel traces
|
|
@@ -202,21 +202,21 @@ class DBOSContext:
|
|
|
202
202
|
##############################################################
|
|
203
203
|
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
_dbos_context_var: ContextVar[Optional[DBOSContext]] = ContextVar(
|
|
206
206
|
"dbos_context", default=None
|
|
207
207
|
)
|
|
208
208
|
|
|
209
209
|
|
|
210
|
-
def
|
|
211
|
-
|
|
210
|
+
def _set_local_dbos_context(ctx: Optional[DBOSContext]) -> None:
|
|
211
|
+
_dbos_context_var.set(ctx)
|
|
212
212
|
|
|
213
213
|
|
|
214
|
-
def
|
|
215
|
-
|
|
214
|
+
def _clear_local_dbos_context() -> None:
|
|
215
|
+
_dbos_context_var.set(None)
|
|
216
216
|
|
|
217
217
|
|
|
218
218
|
def get_local_dbos_context() -> Optional[DBOSContext]:
|
|
219
|
-
return
|
|
219
|
+
return _dbos_context_var.get()
|
|
220
220
|
|
|
221
221
|
|
|
222
222
|
def assert_current_dbos_context() -> DBOSContext:
|
|
@@ -239,7 +239,7 @@ class DBOSContextEnsure:
|
|
|
239
239
|
ctx = get_local_dbos_context()
|
|
240
240
|
if ctx is None:
|
|
241
241
|
self.created_ctx = True
|
|
242
|
-
|
|
242
|
+
_set_local_dbos_context(DBOSContext())
|
|
243
243
|
return assert_current_dbos_context()
|
|
244
244
|
|
|
245
245
|
def __exit__(
|
|
@@ -250,7 +250,7 @@ class DBOSContextEnsure:
|
|
|
250
250
|
) -> Literal[False]:
|
|
251
251
|
# Code to clean up the basic context if we created it
|
|
252
252
|
if self.created_ctx:
|
|
253
|
-
|
|
253
|
+
_clear_local_dbos_context()
|
|
254
254
|
return False # Did not handle
|
|
255
255
|
|
|
256
256
|
|
|
@@ -261,7 +261,7 @@ class DBOSContextSwap:
|
|
|
261
261
|
|
|
262
262
|
def __enter__(self) -> DBOSContextSwap:
|
|
263
263
|
self.prev_ctx = get_local_dbos_context()
|
|
264
|
-
|
|
264
|
+
_set_local_dbos_context(self.next_ctx)
|
|
265
265
|
return self
|
|
266
266
|
|
|
267
267
|
def __exit__(
|
|
@@ -271,7 +271,7 @@ class DBOSContextSwap:
|
|
|
271
271
|
traceback: Optional[TracebackType],
|
|
272
272
|
) -> Literal[False]:
|
|
273
273
|
assert get_local_dbos_context() == self.next_ctx
|
|
274
|
-
|
|
274
|
+
_set_local_dbos_context(self.prev_ctx)
|
|
275
275
|
return False # Did not handle
|
|
276
276
|
|
|
277
277
|
|
|
@@ -301,7 +301,7 @@ class SetWorkflowID:
|
|
|
301
301
|
ctx = get_local_dbos_context()
|
|
302
302
|
if ctx is None:
|
|
303
303
|
self.created_ctx = True
|
|
304
|
-
|
|
304
|
+
_set_local_dbos_context(DBOSContext())
|
|
305
305
|
assert_current_dbos_context().id_assigned_for_next_workflow = self.wfid
|
|
306
306
|
return self
|
|
307
307
|
|
|
@@ -313,7 +313,7 @@ class SetWorkflowID:
|
|
|
313
313
|
) -> Literal[False]:
|
|
314
314
|
# Code to clean up the basic context if we created it
|
|
315
315
|
if self.created_ctx:
|
|
316
|
-
|
|
316
|
+
_clear_local_dbos_context()
|
|
317
317
|
return False # Did not handle
|
|
318
318
|
|
|
319
319
|
|
|
@@ -326,7 +326,7 @@ class SetWorkflowRecovery:
|
|
|
326
326
|
ctx = get_local_dbos_context()
|
|
327
327
|
if ctx is None:
|
|
328
328
|
self.created_ctx = True
|
|
329
|
-
|
|
329
|
+
_set_local_dbos_context(DBOSContext())
|
|
330
330
|
assert_current_dbos_context().in_recovery = True
|
|
331
331
|
|
|
332
332
|
return self
|
|
@@ -341,7 +341,7 @@ class SetWorkflowRecovery:
|
|
|
341
341
|
assert_current_dbos_context().in_recovery = False
|
|
342
342
|
# Code to clean up the basic context if we created it
|
|
343
343
|
if self.created_ctx:
|
|
344
|
-
|
|
344
|
+
_clear_local_dbos_context()
|
|
345
345
|
return False # Did not handle
|
|
346
346
|
|
|
347
347
|
|
|
@@ -356,7 +356,7 @@ class EnterDBOSWorkflow(AbstractContextManager[DBOSContext, Literal[False]]):
|
|
|
356
356
|
if ctx is None:
|
|
357
357
|
self.created_ctx = True
|
|
358
358
|
ctx = DBOSContext()
|
|
359
|
-
|
|
359
|
+
_set_local_dbos_context(ctx)
|
|
360
360
|
assert not ctx.is_within_workflow()
|
|
361
361
|
ctx.start_workflow(
|
|
362
362
|
None, self.attributes
|
|
@@ -374,7 +374,7 @@ class EnterDBOSWorkflow(AbstractContextManager[DBOSContext, Literal[False]]):
|
|
|
374
374
|
ctx.end_workflow(exc_value)
|
|
375
375
|
# Code to clean up the basic context if we created it
|
|
376
376
|
if self.created_ctx:
|
|
377
|
-
|
|
377
|
+
_clear_local_dbos_context()
|
|
378
378
|
return False # Did not handle
|
|
379
379
|
|
|
380
380
|
|
|
@@ -394,7 +394,7 @@ class EnterDBOSChildWorkflow(AbstractContextManager[DBOSContext, Literal[False]]
|
|
|
394
394
|
ctx.workflow_id + "-" + str(ctx.function_id)
|
|
395
395
|
)
|
|
396
396
|
self.child_ctx = ctx.create_child()
|
|
397
|
-
|
|
397
|
+
_set_local_dbos_context(self.child_ctx)
|
|
398
398
|
self.child_ctx.start_workflow(None, attributes=self.attributes)
|
|
399
399
|
return self.child_ctx
|
|
400
400
|
|
|
@@ -409,7 +409,7 @@ class EnterDBOSChildWorkflow(AbstractContextManager[DBOSContext, Literal[False]]
|
|
|
409
409
|
ctx.end_workflow(exc_value)
|
|
410
410
|
# Return to parent ctx
|
|
411
411
|
assert self.parent_ctx
|
|
412
|
-
|
|
412
|
+
_set_local_dbos_context(self.parent_ctx)
|
|
413
413
|
return False # Did not handle
|
|
414
414
|
|
|
415
415
|
|
|
@@ -473,7 +473,7 @@ class EnterDBOSHandler:
|
|
|
473
473
|
ctx = get_local_dbos_context()
|
|
474
474
|
if ctx is None:
|
|
475
475
|
self.created_ctx = True
|
|
476
|
-
|
|
476
|
+
_set_local_dbos_context(DBOSContext())
|
|
477
477
|
ctx = assert_current_dbos_context()
|
|
478
478
|
ctx.start_handler(self.attributes)
|
|
479
479
|
return self
|
|
@@ -488,7 +488,7 @@ class EnterDBOSHandler:
|
|
|
488
488
|
ctx.end_handler(exc_value)
|
|
489
489
|
# Code to clean up the basic context if we created it
|
|
490
490
|
if self.created_ctx:
|
|
491
|
-
|
|
491
|
+
_clear_local_dbos_context()
|
|
492
492
|
return False # Did not handle
|
|
493
493
|
|
|
494
494
|
|
|
@@ -504,7 +504,7 @@ class DBOSContextSetAuth(DBOSContextEnsure):
|
|
|
504
504
|
ctx = get_local_dbos_context()
|
|
505
505
|
if ctx is None:
|
|
506
506
|
self.created_ctx = True
|
|
507
|
-
|
|
507
|
+
_set_local_dbos_context(DBOSContext())
|
|
508
508
|
ctx = assert_current_dbos_context()
|
|
509
509
|
self.prev_user = ctx.authenticated_user
|
|
510
510
|
self.prev_roles = ctx.authenticated_roles
|
|
@@ -521,7 +521,7 @@ class DBOSContextSetAuth(DBOSContextEnsure):
|
|
|
521
521
|
ctx.set_authentication(self.prev_user, self.prev_roles)
|
|
522
522
|
# Clean up the basic context if we created it
|
|
523
523
|
if self.created_ctx:
|
|
524
|
-
|
|
524
|
+
_clear_local_dbos_context()
|
|
525
525
|
return False # Did not handle
|
|
526
526
|
|
|
527
527
|
|