dbos 0.13.0a2__py3-none-any.whl → 0.14.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/_dbos.py +20 -11
- dbos/_dbos_config.py +2 -2
- dbos/_sys_db.py +7 -0
- dbos/cli.py +76 -5
- {dbos-0.13.0a2.dist-info → dbos-0.14.0.dist-info}/METADATA +2 -1
- {dbos-0.13.0a2.dist-info → dbos-0.14.0.dist-info}/RECORD +9 -9
- {dbos-0.13.0a2.dist-info → dbos-0.14.0.dist-info}/WHEEL +0 -0
- {dbos-0.13.0a2.dist-info → dbos-0.14.0.dist-info}/entry_points.txt +0 -0
- {dbos-0.13.0a2.dist-info → dbos-0.14.0.dist-info}/licenses/LICENSE +0 -0
dbos/_dbos.py
CHANGED
|
@@ -238,13 +238,14 @@ class DBOS:
|
|
|
238
238
|
return _dbos_global_instance
|
|
239
239
|
|
|
240
240
|
@classmethod
|
|
241
|
-
def destroy(cls) -> None:
|
|
241
|
+
def destroy(cls, *, destroy_registry: bool = True) -> None:
|
|
242
242
|
global _dbos_global_instance
|
|
243
|
-
global _dbos_global_registry
|
|
244
243
|
if _dbos_global_instance is not None:
|
|
245
244
|
_dbos_global_instance._destroy()
|
|
246
245
|
_dbos_global_instance = None
|
|
247
|
-
|
|
246
|
+
if destroy_registry:
|
|
247
|
+
global _dbos_global_registry
|
|
248
|
+
_dbos_global_registry = None
|
|
248
249
|
|
|
249
250
|
def __init__(
|
|
250
251
|
self,
|
|
@@ -619,16 +620,24 @@ class DBOS:
|
|
|
619
620
|
It is important to use `DBOS.sleep` (as opposed to any other sleep) within workflows,
|
|
620
621
|
as the `DBOS.sleep`s are durable and completed sleeps will be skipped during recovery.
|
|
621
622
|
"""
|
|
622
|
-
|
|
623
|
-
attributes: TracedAttributes = {
|
|
624
|
-
"name": "sleep",
|
|
625
|
-
}
|
|
626
623
|
if seconds <= 0:
|
|
627
624
|
return
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
625
|
+
cur_ctx = get_local_dbos_context()
|
|
626
|
+
if cur_ctx is not None:
|
|
627
|
+
# Must call it within a workflow
|
|
628
|
+
assert (
|
|
629
|
+
cur_ctx.is_workflow()
|
|
630
|
+
), "sleep() must be called from within a workflow"
|
|
631
|
+
attributes: TracedAttributes = {
|
|
632
|
+
"name": "sleep",
|
|
633
|
+
}
|
|
634
|
+
with EnterDBOSStep(attributes) as ctx:
|
|
635
|
+
_get_dbos_instance()._sys_db.sleep(
|
|
636
|
+
ctx.workflow_id, ctx.curr_step_function_id, seconds
|
|
637
|
+
)
|
|
638
|
+
else:
|
|
639
|
+
# Cannot call it from outside of a workflow
|
|
640
|
+
raise DBOSException("sleep() must be called from within a workflow")
|
|
632
641
|
|
|
633
642
|
@classmethod
|
|
634
643
|
def set_event(cls, key: str, value: Any) -> None:
|
dbos/_dbos_config.py
CHANGED
|
@@ -169,7 +169,7 @@ def load_config(config_file_path: str = "dbos-config.yaml") -> ConfigFile:
|
|
|
169
169
|
|
|
170
170
|
if not _is_valid_app_name(data["name"]):
|
|
171
171
|
raise DBOSInitializationError(
|
|
172
|
-
f'Invalid app name {data["name"]}. App names must be between 3 and 30 characters and contain only
|
|
172
|
+
f'Invalid app name {data["name"]}. App names must be between 3 and 30 characters long and contain only lowercase letters, numbers, dashes, and underscores.'
|
|
173
173
|
)
|
|
174
174
|
|
|
175
175
|
if "app_db_name" not in data["database"]:
|
|
@@ -198,4 +198,4 @@ def _app_name_to_db_name(app_name: str) -> str:
|
|
|
198
198
|
def _set_env_vars(config: ConfigFile) -> None:
|
|
199
199
|
for env, value in config.get("env", {}).items():
|
|
200
200
|
if value is not None:
|
|
201
|
-
os.environ[env] = value
|
|
201
|
+
os.environ[env] = str(value)
|
dbos/_sys_db.py
CHANGED
|
@@ -299,6 +299,12 @@ class SystemDatabase:
|
|
|
299
299
|
recovery_attempts: int = row[0]
|
|
300
300
|
if recovery_attempts > max_recovery_attempts:
|
|
301
301
|
with self.engine.begin() as c:
|
|
302
|
+
c.execute(
|
|
303
|
+
sa.delete(SystemSchema.workflow_queue).where(
|
|
304
|
+
SystemSchema.workflow_queue.c.workflow_uuid
|
|
305
|
+
== status["workflow_uuid"]
|
|
306
|
+
)
|
|
307
|
+
)
|
|
302
308
|
c.execute(
|
|
303
309
|
sa.update(SystemSchema.workflow_status)
|
|
304
310
|
.where(
|
|
@@ -311,6 +317,7 @@ class SystemDatabase:
|
|
|
311
317
|
)
|
|
312
318
|
.values(
|
|
313
319
|
status=WorkflowStatusString.RETRIES_EXCEEDED.value,
|
|
320
|
+
queue_name=None,
|
|
314
321
|
)
|
|
315
322
|
)
|
|
316
323
|
raise DBOSDeadLetterQueueError(
|
dbos/cli.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import platform
|
|
3
|
-
import re
|
|
4
3
|
import shutil
|
|
5
4
|
import signal
|
|
6
5
|
import subprocess
|
|
@@ -9,12 +8,15 @@ import typing
|
|
|
9
8
|
from os import path
|
|
10
9
|
from typing import Any
|
|
11
10
|
|
|
11
|
+
import sqlalchemy as sa
|
|
12
12
|
import tomlkit
|
|
13
13
|
import typer
|
|
14
14
|
from rich import print
|
|
15
15
|
from rich.prompt import Prompt
|
|
16
16
|
from typing_extensions import Annotated
|
|
17
17
|
|
|
18
|
+
from dbos._schemas.system_database import SystemSchema
|
|
19
|
+
|
|
18
20
|
from . import load_config
|
|
19
21
|
from ._app_db import ApplicationDatabase
|
|
20
22
|
from ._dbos_config import _is_valid_app_name
|
|
@@ -27,7 +29,9 @@ def _on_windows() -> bool:
|
|
|
27
29
|
return platform.system() == "Windows"
|
|
28
30
|
|
|
29
31
|
|
|
30
|
-
@app.command(
|
|
32
|
+
@app.command(
|
|
33
|
+
help="Start your DBOS application using the start commands in 'dbos-config.yaml'"
|
|
34
|
+
)
|
|
31
35
|
def start() -> None:
|
|
32
36
|
config = load_config()
|
|
33
37
|
start_commands = config["runtimeConfig"]["start"]
|
|
@@ -166,7 +170,7 @@ def _get_project_name() -> typing.Union[str, None]:
|
|
|
166
170
|
return name
|
|
167
171
|
|
|
168
172
|
|
|
169
|
-
@app.command()
|
|
173
|
+
@app.command(help="Initialize a new DBOS application from a template")
|
|
170
174
|
def init(
|
|
171
175
|
project_name: Annotated[
|
|
172
176
|
typing.Optional[str], typer.Argument(help="Specify application name")
|
|
@@ -187,7 +191,9 @@ def init(
|
|
|
187
191
|
)
|
|
188
192
|
|
|
189
193
|
if not _is_valid_app_name(project_name):
|
|
190
|
-
raise Exception(
|
|
194
|
+
raise Exception(
|
|
195
|
+
f"{project_name} is an invalid DBOS app name. App names must be between 3 and 30 characters long and contain only lowercase letters, numbers, dashes, and underscores."
|
|
196
|
+
)
|
|
191
197
|
|
|
192
198
|
templates_dir = _get_templates_directory()
|
|
193
199
|
templates = [x.name for x in os.scandir(templates_dir) if x.is_dir()]
|
|
@@ -212,7 +218,9 @@ def init(
|
|
|
212
218
|
print(f"[red]{e}[/red]")
|
|
213
219
|
|
|
214
220
|
|
|
215
|
-
@app.command(
|
|
221
|
+
@app.command(
|
|
222
|
+
help="Run your database schema migrations using the migration commands in 'dbos-config.yaml'"
|
|
223
|
+
)
|
|
216
224
|
def migrate() -> None:
|
|
217
225
|
config = load_config()
|
|
218
226
|
if not config["database"]["password"]:
|
|
@@ -262,5 +270,68 @@ def migrate() -> None:
|
|
|
262
270
|
typer.echo(f"Completed schema migration for database {app_db_name}")
|
|
263
271
|
|
|
264
272
|
|
|
273
|
+
@app.command(help="Reset the DBOS system database")
|
|
274
|
+
def reset(
|
|
275
|
+
yes: bool = typer.Option(False, "-y", "--yes", help="Skip confirmation prompt")
|
|
276
|
+
) -> None:
|
|
277
|
+
if not yes:
|
|
278
|
+
confirm = typer.confirm(
|
|
279
|
+
"This command resets your DBOS system database, deleting metadata about past workflows and steps. Are you sure you want to proceed?"
|
|
280
|
+
)
|
|
281
|
+
if not confirm:
|
|
282
|
+
typer.echo("Operation cancelled.")
|
|
283
|
+
raise typer.Exit()
|
|
284
|
+
config = load_config()
|
|
285
|
+
sysdb_name = (
|
|
286
|
+
config["database"]["sys_db_name"]
|
|
287
|
+
if "sys_db_name" in config["database"] and config["database"]["sys_db_name"]
|
|
288
|
+
else config["database"]["app_db_name"] + SystemSchema.sysdb_suffix
|
|
289
|
+
)
|
|
290
|
+
postgres_db_url = sa.URL.create(
|
|
291
|
+
"postgresql+psycopg",
|
|
292
|
+
username=config["database"]["username"],
|
|
293
|
+
password=config["database"]["password"],
|
|
294
|
+
host=config["database"]["hostname"],
|
|
295
|
+
port=config["database"]["port"],
|
|
296
|
+
database="postgres",
|
|
297
|
+
)
|
|
298
|
+
try:
|
|
299
|
+
# Connect to postgres default database
|
|
300
|
+
engine = sa.create_engine(postgres_db_url)
|
|
301
|
+
|
|
302
|
+
with engine.connect() as conn:
|
|
303
|
+
# Set autocommit required for database dropping
|
|
304
|
+
conn.execution_options(isolation_level="AUTOCOMMIT")
|
|
305
|
+
|
|
306
|
+
# Terminate existing connections
|
|
307
|
+
conn.execute(
|
|
308
|
+
sa.text(
|
|
309
|
+
"""
|
|
310
|
+
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
311
|
+
FROM pg_stat_activity
|
|
312
|
+
WHERE pg_stat_activity.datname = :db_name
|
|
313
|
+
AND pid <> pg_backend_pid()
|
|
314
|
+
"""
|
|
315
|
+
),
|
|
316
|
+
{"db_name": sysdb_name},
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
# Drop the database
|
|
320
|
+
conn.execute(sa.text(f"DROP DATABASE IF EXISTS {sysdb_name}"))
|
|
321
|
+
|
|
322
|
+
except sa.exc.SQLAlchemyError as e:
|
|
323
|
+
typer.echo(f"Error dropping database: {str(e)}")
|
|
324
|
+
return
|
|
325
|
+
|
|
326
|
+
sys_db = None
|
|
327
|
+
try:
|
|
328
|
+
sys_db = SystemDatabase(config)
|
|
329
|
+
except Exception as e:
|
|
330
|
+
typer.echo(f"DBOS system schema migration failed: {e}")
|
|
331
|
+
finally:
|
|
332
|
+
if sys_db:
|
|
333
|
+
sys_db.destroy()
|
|
334
|
+
|
|
335
|
+
|
|
265
336
|
if __name__ == "__main__":
|
|
266
337
|
app()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dbos
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: Ultra-lightweight durable execution in Python
|
|
5
5
|
Author-Email: "DBOS, Inc." <contact@dbos.dev>
|
|
6
6
|
License: MIT
|
|
@@ -18,6 +18,7 @@ Requires-Dist: python-dateutil>=2.9.0.post0
|
|
|
18
18
|
Requires-Dist: fastapi[standard]>=0.115.2
|
|
19
19
|
Requires-Dist: tomlkit>=0.13.2
|
|
20
20
|
Requires-Dist: psycopg[binary]>=3.1
|
|
21
|
+
Requires-Dist: fastapi-cli==0.0.5
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
22
23
|
|
|
23
24
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
dbos-0.
|
|
2
|
-
dbos-0.
|
|
3
|
-
dbos-0.
|
|
4
|
-
dbos-0.
|
|
1
|
+
dbos-0.14.0.dist-info/METADATA,sha256=htu3e3yF0MFq_mXKBFHddYckIjWK8hNwaTpQ5QQH5l4,5020
|
|
2
|
+
dbos-0.14.0.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
|
3
|
+
dbos-0.14.0.dist-info/entry_points.txt,sha256=z6GcVANQV7Uw_82H9Ob2axJX6V3imftyZsljdh-M1HU,54
|
|
4
|
+
dbos-0.14.0.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
|
|
5
5
|
dbos/__init__.py,sha256=CxRHBHEthPL4PZoLbZhp3rdm44-KkRTT2-7DkK9d4QQ,724
|
|
6
6
|
dbos/_admin_sever.py,sha256=DOgzVp9kmwiebQqmJB1LcrZnGTxSMbZiGXdenc1wZDg,3163
|
|
7
7
|
dbos/_app_db.py,sha256=_tv2vmPjjiaikwgxH3mqxgJ4nUUcG2-0uMXKWCqVu1c,5509
|
|
@@ -9,8 +9,8 @@ dbos/_classproperty.py,sha256=f0X-_BySzn3yFDRKB2JpCbLYQ9tLwt1XftfshvY7CBs,626
|
|
|
9
9
|
dbos/_context.py,sha256=SJZTOB-saxCNNGT2LLop9LasqR-X2MQLTay3rjXRUCw,17748
|
|
10
10
|
dbos/_core.py,sha256=HUteo2HP9C4UvB-y41xwUphLZyYRTdb0sW5XqZ6QPAY,31167
|
|
11
11
|
dbos/_croniter.py,sha256=hbhgfsHBqclUS8VeLnJ9PSE9Z54z6mi4nnrr1aUXn0k,47561
|
|
12
|
-
dbos/_dbos.py,sha256=
|
|
13
|
-
dbos/_dbos_config.py,sha256=
|
|
12
|
+
dbos/_dbos.py,sha256=mwGxLKWjgA_xheMzLsjHFqFxxp2zOWQX3Epwx06oU8A,31477
|
|
13
|
+
dbos/_dbos_config.py,sha256=6G-S-43XMtkB06WnQ_8dHX-Yf64NdDPLbOkS0qztORk,6375
|
|
14
14
|
dbos/_error.py,sha256=UETk8CoZL-TO2Utn1-E7OSWelhShWmKM-fOlODMR9PE,3893
|
|
15
15
|
dbos/_fastapi.py,sha256=iyefCZq-ZDKRUjN_rgYQmFmyvWf4gPrSlC6CLbfq4a8,3419
|
|
16
16
|
dbos/_flask.py,sha256=z1cijbTi5Dpq6kqikPCx1LcR2YHHv2oc41NehOWjw74,2431
|
|
@@ -35,7 +35,7 @@ dbos/_schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
35
35
|
dbos/_schemas/application_database.py,sha256=KeyoPrF7hy_ODXV7QNike_VFSD74QBRfQ76D7QyE9HI,966
|
|
36
36
|
dbos/_schemas/system_database.py,sha256=7iw7eHJzEvkatHMOaHORoSvtfisF73wW5j8hRt_Ph14,5126
|
|
37
37
|
dbos/_serialization.py,sha256=YCYv0qKAwAZ1djZisBC7khvKqG-5OcIv9t9EC5PFIog,1743
|
|
38
|
-
dbos/_sys_db.py,sha256=
|
|
38
|
+
dbos/_sys_db.py,sha256=NyakKa8lGMJ4WHydwukB8QubyGV9A6feK_bVepknZr4,48887
|
|
39
39
|
dbos/_templates/hello/README.md,sha256=GhxhBj42wjTt1fWEtwNriHbJuKb66Vzu89G4pxNHw2g,930
|
|
40
40
|
dbos/_templates/hello/__package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
41
|
dbos/_templates/hello/__package/main.py,sha256=eI0SS9Nwj-fldtiuSzIlIG6dC91GXXwdRsoHxv6S_WI,2719
|
|
@@ -47,8 +47,8 @@ dbos/_templates/hello/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1u
|
|
|
47
47
|
dbos/_templates/hello/migrations/versions/2024_07_31_180642_init.py,sha256=U5thFWGqNN4QLrNXT7wUUqftIFDNE5eSdqD8JNW1mec,942
|
|
48
48
|
dbos/_templates/hello/start_postgres_docker.py,sha256=lQVLlYO5YkhGPEgPqwGc7Y8uDKse9HsWv5fynJEFJHM,1681
|
|
49
49
|
dbos/_tracer.py,sha256=rvBY1RQU6DO7rL7EnaJJxGcmd4tP_PpGqUEE6imZnhY,2518
|
|
50
|
-
dbos/cli.py,sha256=
|
|
50
|
+
dbos/cli.py,sha256=em1uAxrp5yyg53V7ZpmHFtqD6OJp2cMJkG9vGJPoFTA,10904
|
|
51
51
|
dbos/dbos-config.schema.json,sha256=tgtiirOTEdIRI27eI75UAER9sAV84CDnv5lRPt0qiuQ,5672
|
|
52
52
|
dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
|
|
53
53
|
version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
|
|
54
|
-
dbos-0.
|
|
54
|
+
dbos-0.14.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|