dbos 1.15.0a1__py3-none-any.whl → 1.15.0a2__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/_client.py CHANGED
@@ -22,11 +22,7 @@ from dbos._sys_db import SystemDatabase
22
22
  if TYPE_CHECKING:
23
23
  from dbos._dbos import WorkflowHandle, WorkflowHandleAsync
24
24
 
25
- from dbos._dbos_config import (
26
- get_application_database_url,
27
- get_system_database_url,
28
- is_valid_database_url,
29
- )
25
+ from dbos._dbos_config import get_system_database_url, is_valid_database_url
30
26
  from dbos._error import DBOSException, DBOSNonExistentWorkflowError
31
27
  from dbos._registrations import DEFAULT_MAX_RECOVERY_ATTEMPTS
32
28
  from dbos._serialization import WorkflowInputs
@@ -118,6 +114,9 @@ class WorkflowHandleClientAsyncPolling(Generic[R]):
118
114
 
119
115
 
120
116
  class DBOSClient:
117
+
118
+ _app_db: ApplicationDatabase | None = None
119
+
121
120
  def __init__(
122
121
  self,
123
122
  database_url: Optional[str] = None, # DEPRECATED
@@ -126,13 +125,8 @@ class DBOSClient:
126
125
  application_database_url: Optional[str] = None,
127
126
  system_database: Optional[str] = None, # DEPRECATED
128
127
  ):
129
- application_database_url = get_application_database_url(
130
- {
131
- "system_database_url": system_database_url,
132
- "database_url": (
133
- database_url if database_url else application_database_url
134
- ),
135
- }
128
+ application_database_url = (
129
+ database_url if database_url else application_database_url
136
130
  )
137
131
  system_database_url = get_system_database_url(
138
132
  {
@@ -142,7 +136,8 @@ class DBOSClient:
142
136
  }
143
137
  )
144
138
  assert is_valid_database_url(system_database_url)
145
- assert is_valid_database_url(application_database_url)
139
+ if application_database_url:
140
+ assert is_valid_database_url(application_database_url)
146
141
  # We only create database connections but do not run migrations
147
142
  self._sys_db = SystemDatabase.create(
148
143
  system_database_url=system_database_url,
@@ -153,14 +148,15 @@ class DBOSClient:
153
148
  },
154
149
  )
155
150
  self._sys_db.check_connection()
156
- self._app_db = ApplicationDatabase.create(
157
- database_url=application_database_url,
158
- engine_kwargs={
159
- "pool_timeout": 30,
160
- "max_overflow": 0,
161
- "pool_size": 2,
162
- },
163
- )
151
+ if application_database_url:
152
+ self._app_db = ApplicationDatabase.create(
153
+ database_url=application_database_url,
154
+ engine_kwargs={
155
+ "pool_timeout": 30,
156
+ "max_overflow": 0,
157
+ "pool_size": 2,
158
+ },
159
+ )
164
160
 
165
161
  def destroy(self) -> None:
166
162
  self._sys_db.destroy()
dbos/_core.py CHANGED
@@ -896,7 +896,9 @@ def decorate_transaction(
896
896
  raise DBOSWorkflowCancelledError(
897
897
  f"Workflow {ctx.workflow_id} is cancelled. Aborting transaction {transaction_name}."
898
898
  )
899
-
899
+ assert (
900
+ dbos._app_db
901
+ ), "Transactions can only be used if DBOS is configured with an application_database_url"
900
902
  with dbos._app_db.sessionmaker() as session:
901
903
  attributes: TracedAttributes = {
902
904
  "name": transaction_name,
dbos/_dbos.py CHANGED
@@ -409,13 +409,8 @@ class DBOS:
409
409
  return rv
410
410
 
411
411
  @property
412
- def _app_db(self) -> ApplicationDatabase:
413
- if self._app_db_field is None:
414
- raise DBOSException(
415
- "Application database accessed before DBOS was launched"
416
- )
417
- rv: ApplicationDatabase = self._app_db_field
418
- return rv
412
+ def _app_db(self) -> ApplicationDatabase | None:
413
+ return self._app_db_field
419
414
 
420
415
  @property
421
416
  def _admin_server(self) -> AdminServer:
@@ -448,7 +443,6 @@ class DBOS:
448
443
  dbos_logger.info(f"Application version: {GlobalParams.app_version}")
449
444
  self._executor_field = ThreadPoolExecutor(max_workers=sys.maxsize)
450
445
  self._background_event_loop.start()
451
- assert self._config["database_url"] is not None
452
446
  assert self._config["database"]["sys_db_engine_kwargs"] is not None
453
447
  self._sys_db_field = SystemDatabase.create(
454
448
  system_database_url=get_system_database_url(self._config),
@@ -456,18 +450,20 @@ class DBOS:
456
450
  debug_mode=debug_mode,
457
451
  )
458
452
  assert self._config["database"]["db_engine_kwargs"] is not None
459
- self._app_db_field = ApplicationDatabase.create(
460
- database_url=self._config["database_url"],
461
- engine_kwargs=self._config["database"]["db_engine_kwargs"],
462
- debug_mode=debug_mode,
463
- )
453
+ if self._config["database_url"]:
454
+ self._app_db_field = ApplicationDatabase.create(
455
+ database_url=self._config["database_url"],
456
+ engine_kwargs=self._config["database"]["db_engine_kwargs"],
457
+ debug_mode=debug_mode,
458
+ )
464
459
 
465
460
  if debug_mode:
466
461
  return
467
462
 
468
463
  # Run migrations for the system and application databases
469
464
  self._sys_db.run_migrations()
470
- self._app_db.run_migrations()
465
+ if self._app_db:
466
+ self._app_db.run_migrations()
471
467
 
472
468
  admin_port = self._config.get("runtimeConfig", {}).get("admin_port")
473
469
  if admin_port is None:
dbos/_dbos_config.py CHANGED
@@ -408,22 +408,20 @@ def process_config(
408
408
  url = url.set(database=f"{url.database}{SystemSchema.sysdb_suffix}")
409
409
  data["system_database_url"] = url.render_as_string(hide_password=False)
410
410
 
411
- # If a system database URL is provided but not an application database URL, set the
412
- # application database URL to the system database URL.
411
+ # If a system database URL is provided but not an application database URL,
412
+ # do not create an application database.
413
413
  if data.get("system_database_url") and not data.get("database_url"):
414
414
  assert data["system_database_url"]
415
- data["database_url"] = data["system_database_url"]
415
+ data["database_url"] = None
416
416
 
417
- # If neither URL is provided, use a default SQLite database URL.
417
+ # If neither URL is provided, use a default SQLite system database URL.
418
418
  if not data.get("database_url") and not data.get("system_database_url"):
419
419
  _app_db_name = _app_name_to_db_name(data["name"])
420
- data["system_database_url"] = data["database_url"] = (
421
- f"sqlite:///{_app_db_name}.sqlite"
422
- )
420
+ data["system_database_url"] = f"sqlite:///{_app_db_name}.sqlite"
421
+ data["database_url"] = None
423
422
 
424
423
  configure_db_engine_parameters(data["database"], connect_timeout=connect_timeout)
425
424
 
426
- assert data["database_url"] is not None
427
425
  assert data["system_database_url"] is not None
428
426
  # Pretty-print connection information, respecting log level
429
427
  if not silent and logs["logLevel"] == "INFO" or logs["logLevel"] == "DEBUG":
@@ -431,7 +429,12 @@ def process_config(
431
429
  hide_password=True
432
430
  )
433
431
  print(f"DBOS system database URL: {printable_sys_db_url}")
434
- if data["database_url"].startswith("sqlite"):
432
+ if data["database_url"]:
433
+ printable_app_db_url = make_url(data["database_url"]).render_as_string(
434
+ hide_password=True
435
+ )
436
+ print(f"DBOS application database URL: {printable_app_db_url}")
437
+ if data["system_database_url"].startswith("sqlite"):
435
438
  print(
436
439
  f"Using SQLite as a system database. The SQLite system database is for development and testing. PostgreSQL is recommended for production use."
437
440
  )
@@ -615,12 +618,11 @@ def get_system_database_url(config: ConfigFile) -> str:
615
618
  )
616
619
 
617
620
 
618
- def get_application_database_url(config: ConfigFile) -> str:
621
+ def get_application_database_url(config: ConfigFile) -> str | None:
619
622
  # For backwards compatibility, the application database URL is "database_url"
620
623
  if config.get("database_url"):
621
624
  assert config["database_url"]
622
625
  return config["database_url"]
623
626
  else:
624
- # If the application database URL is not specified, set it to the system database URL
625
- assert config["system_database_url"]
626
- return config["system_database_url"]
627
+ # If the application database URL is not specified, return None
628
+ return None
@@ -98,10 +98,10 @@ def get_workflow(sys_db: SystemDatabase, workflow_id: str) -> Optional[WorkflowS
98
98
 
99
99
 
100
100
  def list_workflow_steps(
101
- sys_db: SystemDatabase, app_db: ApplicationDatabase, workflow_id: str
101
+ sys_db: SystemDatabase, app_db: Optional[ApplicationDatabase], workflow_id: str
102
102
  ) -> List[StepInfo]:
103
103
  steps = sys_db.get_workflow_steps(workflow_id)
104
- transactions = app_db.get_transactions(workflow_id)
104
+ transactions = app_db.get_transactions(workflow_id) if app_db else []
105
105
  merged_steps = steps + transactions
106
106
  merged_steps.sort(key=lambda step: step["function_id"])
107
107
  return merged_steps
@@ -109,7 +109,7 @@ def list_workflow_steps(
109
109
 
110
110
  def fork_workflow(
111
111
  sys_db: SystemDatabase,
112
- app_db: ApplicationDatabase,
112
+ app_db: Optional[ApplicationDatabase],
113
113
  workflow_id: str,
114
114
  start_step: int,
115
115
  *,
@@ -122,7 +122,8 @@ def fork_workflow(
122
122
  ctx.id_assigned_for_next_workflow = ""
123
123
  else:
124
124
  forked_workflow_id = str(uuid.uuid4())
125
- app_db.clone_workflow_transactions(workflow_id, forked_workflow_id, start_step)
125
+ if app_db:
126
+ app_db.clone_workflow_transactions(workflow_id, forked_workflow_id, start_step)
126
127
  sys_db.fork_workflow(
127
128
  workflow_id,
128
129
  forked_workflow_id,
@@ -145,7 +146,10 @@ def garbage_collect(
145
146
  )
146
147
  if result is not None:
147
148
  cutoff_epoch_timestamp_ms, pending_workflow_ids = result
148
- dbos._app_db.garbage_collect(cutoff_epoch_timestamp_ms, pending_workflow_ids)
149
+ if dbos._app_db:
150
+ dbos._app_db.garbage_collect(
151
+ cutoff_epoch_timestamp_ms, pending_workflow_ids
152
+ )
149
153
 
150
154
 
151
155
  def global_timeout(dbos: "DBOS", cutoff_epoch_timestamp_ms: int) -> None:
dbos/cli/cli.py CHANGED
@@ -38,7 +38,7 @@ class DefaultEncoder(json.JSONEncoder):
38
38
 
39
39
  def _get_db_url(
40
40
  *, system_database_url: Optional[str], application_database_url: Optional[str]
41
- ) -> Tuple[str, str]:
41
+ ) -> Tuple[str, str | None]:
42
42
  """
43
43
  Get the database URL to use for the DBOS application.
44
44
  Order of precedence:
@@ -294,7 +294,8 @@ def migrate(
294
294
  )
295
295
 
296
296
  typer.echo(f"Starting DBOS migrations")
297
- typer.echo(f"Application database: {sa.make_url(application_database_url)}")
297
+ if application_database_url:
298
+ typer.echo(f"Application database: {sa.make_url(application_database_url)}")
298
299
  typer.echo(f"System database: {sa.make_url(system_database_url)}")
299
300
 
300
301
  # First, run DBOS migrations on the system database and the application database
@@ -305,9 +306,10 @@ def migrate(
305
306
 
306
307
  # Next, assign permissions on the DBOS schema to the application role, if any
307
308
  if application_role:
308
- grant_dbos_schema_permissions(
309
- database_url=application_database_url, role_name=application_role
310
- )
309
+ if application_database_url:
310
+ grant_dbos_schema_permissions(
311
+ database_url=application_database_url, role_name=application_role
312
+ )
311
313
  grant_dbos_schema_permissions(
312
314
  database_url=system_database_url, role_name=application_role
313
315
  )
dbos/cli/migration.py CHANGED
@@ -1,3 +1,5 @@
1
+ from typing import Optional
2
+
1
3
  import sqlalchemy as sa
2
4
  import typer
3
5
 
@@ -5,7 +7,9 @@ from dbos._app_db import ApplicationDatabase
5
7
  from dbos._sys_db import SystemDatabase
6
8
 
7
9
 
8
- def migrate_dbos_databases(app_database_url: str, system_database_url: str) -> None:
10
+ def migrate_dbos_databases(
11
+ app_database_url: Optional[str], system_database_url: str
12
+ ) -> None:
9
13
  app_db = None
10
14
  sys_db = None
11
15
  try:
@@ -17,16 +21,17 @@ def migrate_dbos_databases(app_database_url: str, system_database_url: str) -> N
17
21
  "pool_size": 2,
18
22
  },
19
23
  )
20
- app_db = ApplicationDatabase.create(
21
- database_url=app_database_url,
22
- engine_kwargs={
23
- "pool_timeout": 30,
24
- "max_overflow": 0,
25
- "pool_size": 2,
26
- },
27
- )
28
24
  sys_db.run_migrations()
29
- app_db.run_migrations()
25
+ if app_database_url:
26
+ app_db = ApplicationDatabase.create(
27
+ database_url=app_database_url,
28
+ engine_kwargs={
29
+ "pool_timeout": 30,
30
+ "max_overflow": 0,
31
+ "pool_size": 2,
32
+ },
33
+ )
34
+ app_db.run_migrations()
30
35
  except Exception as e:
31
36
  typer.echo(f"DBOS migrations failed: {e}")
32
37
  raise typer.Exit(code=1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 1.15.0a1
3
+ Version: 1.15.0a2
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -1,20 +1,20 @@
1
- dbos-1.15.0a1.dist-info/METADATA,sha256=554w5m_z7LQ0LxzPVltRg_qEfahaA1NPkLDLv9g6GMY,13021
2
- dbos-1.15.0a1.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- dbos-1.15.0a1.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
4
- dbos-1.15.0a1.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
1
+ dbos-1.15.0a2.dist-info/METADATA,sha256=STEFFiAPM8uZbNbNRPz81v65hcKlFKT1hiL52v7yjo8,13021
2
+ dbos-1.15.0a2.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ dbos-1.15.0a2.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
4
+ dbos-1.15.0a2.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
5
5
  dbos/__init__.py,sha256=pT4BuNLDCrIQX27vQG8NlfxX6PZRU7r9miq4thJTszU,982
6
6
  dbos/__main__.py,sha256=G7Exn-MhGrVJVDbgNlpzhfh8WMX_72t3_oJaFT9Lmt8,653
7
7
  dbos/_admin_server.py,sha256=e8ELhcDWqR3_PNobnNgUvLGh5lzZq0yFSF6dvtzoQRI,16267
8
8
  dbos/_app_db.py,sha256=GsV-uYU0QsChWwQDxnrh8_iiZ_zMQB-bsP2jPGIe2aM,16094
9
9
  dbos/_classproperty.py,sha256=f0X-_BySzn3yFDRKB2JpCbLYQ9tLwt1XftfshvY7CBs,626
10
- dbos/_client.py,sha256=XW5EQltqkwRgTnHq3avhuBuOTYSZkERrk9GMpqX8kfM,18859
10
+ dbos/_client.py,sha256=zfFQhj_mf4NS85Nlf1xbXwMQVX_mu3UaU7sb8uE5peM,18794
11
11
  dbos/_conductor/conductor.py,sha256=3E_hL3c9g9yWqKZkvI6KA0-ZzPMPRo06TOzT1esMiek,24114
12
12
  dbos/_conductor/protocol.py,sha256=q3rgLxINFtWFigdOONc-4gX4vn66UmMlJQD6Kj8LnL4,7420
13
13
  dbos/_context.py,sha256=cJDxVbswTLXKE5MV4Hmg6gpIX3Dd5mBTG-4lmofWP9E,27668
14
- dbos/_core.py,sha256=Eec_XWwewuwyaJiQwJMv7bWBWQoC3QWXDJsm2hzUVdI,50342
14
+ dbos/_core.py,sha256=13DNN_fpSIs42NquV80XsHV7yKwY_adKP03h_xhXok4,50493
15
15
  dbos/_croniter.py,sha256=XHAyUyibs_59sJQfSNWkP7rqQY6_XrlfuuCxk4jYqek,47559
16
- dbos/_dbos.py,sha256=dMJvLCCPqF31oqxgVF7ydcOgFmy4jRI5ky8AdMReUCQ,57987
17
- dbos/_dbos_config.py,sha256=B1y1hrWJc8UIoWbCqqBRGnc3bainLPp-TC6x1phInk0,25320
16
+ dbos/_dbos.py,sha256=ZrNrFUoND2t8UorqPLjeDvfOP73AasOXqpeuSS6Rz7E,57836
17
+ dbos/_dbos_config.py,sha256=sWXd9RuWGmhkd7j2SraxDWQir_-F2p0SIqGO61ILeyk,25391
18
18
  dbos/_debouncer.py,sha256=VmGq1_ZIQ79fnH14LEhdoqxKWp6rlEwzsUwumwAMgTQ,15095
19
19
  dbos/_debug.py,sha256=0MfgNqutCUhI4PEmmra9x7f3DiFE_0nscfUCHdLimEY,1415
20
20
  dbos/_docker_pg_helper.py,sha256=xySum4hTA8TVMBODoG19u4cXQAB1vCock-jwM2pnmSI,7791
@@ -48,12 +48,12 @@ dbos/_templates/dbos-db-starter/migrations/create_table.py.dbos,sha256=pVm2Q0Asx
48
48
  dbos/_templates/dbos-db-starter/start_postgres_docker.py,sha256=lQVLlYO5YkhGPEgPqwGc7Y8uDKse9HsWv5fynJEFJHM,1681
49
49
  dbos/_tracer.py,sha256=PHbD7iTEkHk7z4B9hc-wPgi2dPTeI1rhZgLI33TQEeM,3786
50
50
  dbos/_utils.py,sha256=ZdoM1MDbHnlJrh31zfhp3iX62bAxK1kyvMwXnltC_84,1779
51
- dbos/_workflow_commands.py,sha256=EmmAaQfRWeOZm_WPTznuU-O3he3jiSzzT9VpYrhxugE,4835
51
+ dbos/_workflow_commands.py,sha256=k-i1bCfNrux43BHLT8wQ-l-MVZX3D6LGZLH7-uuiDRo,4951
52
52
  dbos/cli/_github_init.py,sha256=R_94Fnn40CAmPy-zM00lwHi0ndyfv57TmIooADjmag4,3378
53
53
  dbos/cli/_template_init.py,sha256=AltKk256VocgvxLpuTxpjJyACrdHFjbGoqYhHzeLae4,2649
54
- dbos/cli/cli.py,sha256=-yoFUGzwPiAJlDfCOWr2TfnVw5LvMGqDKDK-ri-HPzw,26631
55
- dbos/cli/migration.py,sha256=5GiyagLZkyVvDz3StYxtFdkFoKFCmh6eSXjzsIGhZ_A,3330
54
+ dbos/cli/cli.py,sha256=8fn8hseZWWseJiJMo21_mWYfMqgM2y7l_3UbMP0YNMI,26724
55
+ dbos/cli/migration.py,sha256=vaYxHy0k5KgEuoOQUl6R9oxKv4V5nKKpaVhRbkLDXpo,3440
56
56
  dbos/dbos-config.schema.json,sha256=LyUT1DOTaAwOP6suxQGS5KemVIqXGPyu_q7Hbo0neA8,6192
57
57
  dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
58
58
  version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
59
- dbos-1.15.0a1.dist-info/RECORD,,
59
+ dbos-1.15.0a2.dist-info/RECORD,,