dbos 0.14.0a2__py3-none-any.whl → 0.14.0a6__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.
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
- _dbos_global_registry = None
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
- with EnterDBOSStep(attributes) as ctx:
629
- _get_dbos_instance()._sys_db.sleep(
630
- ctx.workflow_id, ctx.curr_step_function_id, seconds
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/_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")
@@ -214,7 +218,9 @@ def init(
214
218
  print(f"[red]{e}[/red]")
215
219
 
216
220
 
217
- @app.command()
221
+ @app.command(
222
+ help="Run your database schema migrations using the migration commands in 'dbos-config.yaml'"
223
+ )
218
224
  def migrate() -> None:
219
225
  config = load_config()
220
226
  if not config["database"]["password"]:
@@ -264,5 +270,68 @@ def migrate() -> None:
264
270
  typer.echo(f"Completed schema migration for database {app_db_name}")
265
271
 
266
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
+
267
336
  if __name__ == "__main__":
268
337
  app()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 0.14.0a2
3
+ Version: 0.14.0a6
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -1,7 +1,7 @@
1
- dbos-0.14.0a2.dist-info/METADATA,sha256=pRN4cQVki2JkNvyQlZc33Fi570IAuGuJHNfbhBeTOTc,4988
2
- dbos-0.14.0a2.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- dbos-0.14.0a2.dist-info/entry_points.txt,sha256=z6GcVANQV7Uw_82H9Ob2axJX6V3imftyZsljdh-M1HU,54
4
- dbos-0.14.0a2.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
1
+ dbos-0.14.0a6.dist-info/METADATA,sha256=Ipf6njKnnDmUZ2qtp8tuyJSMKL31tv4C7ljJ_GuIP0U,4988
2
+ dbos-0.14.0a6.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ dbos-0.14.0a6.dist-info/entry_points.txt,sha256=z6GcVANQV7Uw_82H9Ob2axJX6V3imftyZsljdh-M1HU,54
4
+ dbos-0.14.0a6.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,7 +9,7 @@ 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=Or5z_PLwuUOz2wcI4PrBwAQYv7EarGpRU44WbvSU9pw,30986
12
+ dbos/_dbos.py,sha256=mwGxLKWjgA_xheMzLsjHFqFxxp2zOWQX3Epwx06oU8A,31477
13
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
@@ -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=8bPWjrKM7MZSuxbGmC1M9yshG2LqymyedOXUtZedYX8,48538
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=HCK9Pe2lTelTEG1cvKnxalBp0iR2IqBWLOuwRf_Ey1c,8456
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.14.0a2.dist-info/RECORD,,
54
+ dbos-0.14.0a6.dist-info/RECORD,,