dbos 0.26.0a25__tar.gz → 0.27.0a2__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 (104) hide show
  1. {dbos-0.26.0a25 → dbos-0.27.0a2}/PKG-INFO +1 -1
  2. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_app_db.py +16 -4
  3. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_dbos.py +6 -1
  4. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_dbos_config.py +6 -0
  5. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_sys_db.py +15 -5
  6. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_tracer.py +9 -1
  7. {dbos-0.26.0a25 → dbos-0.27.0a2}/pyproject.toml +1 -1
  8. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_config.py +20 -0
  9. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_spans.py +24 -10
  10. {dbos-0.26.0a25 → dbos-0.27.0a2}/LICENSE +0 -0
  11. {dbos-0.26.0a25 → dbos-0.27.0a2}/README.md +0 -0
  12. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/__init__.py +0 -0
  13. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/__main__.py +0 -0
  14. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_admin_server.py +0 -0
  15. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_classproperty.py +0 -0
  16. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_client.py +0 -0
  17. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_conductor/conductor.py +0 -0
  18. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_conductor/protocol.py +0 -0
  19. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_context.py +0 -0
  20. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_core.py +0 -0
  21. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_croniter.py +0 -0
  22. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_debug.py +0 -0
  23. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_docker_pg_helper.py +0 -0
  24. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_error.py +0 -0
  25. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_event_loop.py +0 -0
  26. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_fastapi.py +0 -0
  27. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_flask.py +0 -0
  28. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_kafka.py +0 -0
  29. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_kafka_message.py +0 -0
  30. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_logger.py +0 -0
  31. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/env.py +0 -0
  32. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/script.py.mako +0 -0
  33. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/04ca4f231047_workflow_queues_executor_id.py +0 -0
  34. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/50f3227f0b4b_fix_job_queue.py +0 -0
  35. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/5c361fc04708_added_system_tables.py +0 -0
  36. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/83f3732ae8e7_workflow_timeout.py +0 -0
  37. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/a3b18ad34abe_added_triggers.py +0 -0
  38. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/d76646551a6b_job_queue_limiter.py +0 -0
  39. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/d76646551a6c_workflow_queue.py +0 -0
  40. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/eab0cc1d9a14_job_queue.py +0 -0
  41. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_migrations/versions/f4b9b32ba814_functionname_childid_op_outputs.py +0 -0
  42. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_outcome.py +0 -0
  43. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_queue.py +0 -0
  44. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_recovery.py +0 -0
  45. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_registrations.py +0 -0
  46. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_request.py +0 -0
  47. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_roles.py +0 -0
  48. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_scheduler.py +0 -0
  49. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_schemas/__init__.py +0 -0
  50. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_schemas/application_database.py +0 -0
  51. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_schemas/system_database.py +0 -0
  52. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_serialization.py +0 -0
  53. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/README.md +0 -0
  54. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/__package/__init__.py +0 -0
  55. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/__package/main.py +0 -0
  56. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/__package/schema.py +0 -0
  57. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/alembic.ini +0 -0
  58. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/dbos-config.yaml.dbos +0 -0
  59. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/migrations/env.py.dbos +0 -0
  60. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/migrations/script.py.mako +0 -0
  61. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py +0 -0
  62. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_templates/dbos-db-starter/start_postgres_docker.py +0 -0
  63. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_utils.py +0 -0
  64. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/_workflow_commands.py +0 -0
  65. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/cli/_github_init.py +0 -0
  66. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/cli/_template_init.py +0 -0
  67. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/cli/cli.py +0 -0
  68. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/dbos-config.schema.json +0 -0
  69. {dbos-0.26.0a25 → dbos-0.27.0a2}/dbos/py.typed +0 -0
  70. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/__init__.py +0 -0
  71. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/atexit_no_ctor.py +0 -0
  72. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/atexit_no_launch.py +0 -0
  73. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/classdefs.py +0 -0
  74. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/client_collateral.py +0 -0
  75. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/client_worker.py +0 -0
  76. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/conftest.py +0 -0
  77. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/dupname_classdefs1.py +0 -0
  78. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/dupname_classdefsa.py +0 -0
  79. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/more_classdefs.py +0 -0
  80. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/queuedworkflow.py +0 -0
  81. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_admin_server.py +0 -0
  82. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_async.py +0 -0
  83. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_classdecorators.py +0 -0
  84. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_client.py +0 -0
  85. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_concurrency.py +0 -0
  86. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_croniter.py +0 -0
  87. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_dbos.py +0 -0
  88. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_debug.py +0 -0
  89. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_docker_secrets.py +0 -0
  90. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_failures.py +0 -0
  91. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_fastapi.py +0 -0
  92. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_fastapi_roles.py +0 -0
  93. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_flask.py +0 -0
  94. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_kafka.py +0 -0
  95. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_outcome.py +0 -0
  96. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_package.py +0 -0
  97. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_queue.py +0 -0
  98. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_scheduler.py +0 -0
  99. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_schema_migration.py +0 -0
  100. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_singleton.py +0 -0
  101. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_sqlalchemy.py +0 -0
  102. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_workflow_introspection.py +0 -0
  103. {dbos-0.26.0a25 → dbos-0.27.0a2}/tests/test_workflow_management.py +0 -0
  104. {dbos-0.26.0a25 → dbos-0.27.0a2}/version/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 0.26.0a25
3
+ Version: 0.27.0a2
4
4
  Summary: Ultra-lightweight durable execution in Python
5
5
  Author-Email: "DBOS, Inc." <contact@dbos.dev>
6
6
  License: MIT
@@ -77,12 +77,24 @@ class ApplicationDatabase:
77
77
  pool_size = database.get("app_db_pool_size")
78
78
  if pool_size is None:
79
79
  pool_size = 20
80
+
81
+ engine_kwargs = database.get("db_engine_kwargs")
82
+ if engine_kwargs is None:
83
+ engine_kwargs = {}
84
+
85
+ # Respect user-provided values. Otherwise, set defaults.
86
+ if "pool_size" not in engine_kwargs:
87
+ engine_kwargs["pool_size"] = pool_size
88
+ if "max_overflow" not in engine_kwargs:
89
+ engine_kwargs["max_overflow"] = 0
90
+ if "pool_timeout" not in engine_kwargs:
91
+ engine_kwargs["pool_timeout"] = 30
92
+ if "connect_args" not in engine_kwargs:
93
+ engine_kwargs["connect_args"] = connect_args
94
+
80
95
  self.engine = sa.create_engine(
81
96
  app_db_url,
82
- pool_size=pool_size,
83
- max_overflow=0,
84
- pool_timeout=30,
85
- connect_args=connect_args,
97
+ **engine_kwargs,
86
98
  )
87
99
  self.sessionmaker = sessionmaker(bind=self.engine)
88
100
  self.debug_mode = debug_mode
@@ -65,7 +65,7 @@ from ._registrations import (
65
65
  from ._roles import default_required_roles, required_roles
66
66
  from ._scheduler import ScheduledWorkflow, scheduled
67
67
  from ._sys_db import StepInfo, WorkflowStatus, reset_system_database
68
- from ._tracer import dbos_tracer
68
+ from ._tracer import DBOSTracer, dbos_tracer
69
69
 
70
70
  if TYPE_CHECKING:
71
71
  from fastapi import FastAPI
@@ -1166,6 +1166,11 @@ class DBOS:
1166
1166
  ctx.authenticated_user = authenticated_user
1167
1167
  ctx.authenticated_roles = authenticated_roles
1168
1168
 
1169
+ @classproperty
1170
+ def tracer(self) -> DBOSTracer:
1171
+ """Return the DBOS OpenTelemetry tracer."""
1172
+ return dbos_tracer
1173
+
1169
1174
 
1170
1175
  class WorkflowHandle(Generic[R], Protocol):
1171
1176
  """
@@ -31,6 +31,7 @@ class DBOSConfig(TypedDict, total=False):
31
31
  app_db_pool_size (int): Application database pool size
32
32
  sys_db_name (str): System database name
33
33
  sys_db_pool_size (int): System database pool size
34
+ db_engine_kwargs (Dict[str, Any]): SQLAlchemy engine kwargs (See https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.create_engine)
34
35
  log_level (str): Log level
35
36
  otlp_traces_endpoints: List[str]: OTLP traces endpoints
36
37
  otlp_logs_endpoints: List[str]: OTLP logs endpoints
@@ -43,6 +44,7 @@ class DBOSConfig(TypedDict, total=False):
43
44
  app_db_pool_size: Optional[int]
44
45
  sys_db_name: Optional[str]
45
46
  sys_db_pool_size: Optional[int]
47
+ db_engine_kwargs: Optional[Dict[str, Any]]
46
48
  log_level: Optional[str]
47
49
  otlp_traces_endpoints: Optional[List[str]]
48
50
  otlp_logs_endpoints: Optional[List[str]]
@@ -64,6 +66,7 @@ class DatabaseConfig(TypedDict, total=False):
64
66
  app_db_pool_size (int): Application database pool size
65
67
  sys_db_name (str): System database name
66
68
  sys_db_pool_size (int): System database pool size
69
+ db_engine_kwargs (Dict[str, Any]): SQLAlchemy engine kwargs
67
70
  migrate (List[str]): Migration commands to run on startup
68
71
  """
69
72
 
@@ -76,6 +79,7 @@ class DatabaseConfig(TypedDict, total=False):
76
79
  app_db_pool_size: Optional[int]
77
80
  sys_db_name: Optional[str]
78
81
  sys_db_pool_size: Optional[int]
82
+ db_engine_kwargs: Optional[Dict[str, Any]]
79
83
  ssl: Optional[bool] # Will be removed in a future version
80
84
  ssl_ca: Optional[str] # Will be removed in a future version
81
85
  migrate: Optional[List[str]]
@@ -183,6 +187,8 @@ def translate_dbos_config_to_config_file(config: DBOSConfig) -> ConfigFile:
183
187
  db_config["app_db_pool_size"] = config.get("app_db_pool_size")
184
188
  if "sys_db_pool_size" in config:
185
189
  db_config["sys_db_pool_size"] = config.get("sys_db_pool_size")
190
+ if "db_engine_kwargs" in config:
191
+ db_config["db_engine_kwargs"] = config.get("db_engine_kwargs")
186
192
  if db_config:
187
193
  translated_config["database"] = db_config
188
194
 
@@ -267,12 +267,23 @@ class SystemDatabase:
267
267
  if pool_size is None:
268
268
  pool_size = 20
269
269
 
270
+ engine_kwargs = database.get("db_engine_kwargs")
271
+ if engine_kwargs is None:
272
+ engine_kwargs = {}
273
+
274
+ # Respect user-provided values. Otherwise, set defaults.
275
+ if "pool_size" not in engine_kwargs:
276
+ engine_kwargs["pool_size"] = pool_size
277
+ if "max_overflow" not in engine_kwargs:
278
+ engine_kwargs["max_overflow"] = 0
279
+ if "pool_timeout" not in engine_kwargs:
280
+ engine_kwargs["pool_timeout"] = 30
281
+ if "connect_args" not in engine_kwargs:
282
+ engine_kwargs["connect_args"] = {"connect_timeout": 10}
283
+
270
284
  self.engine = sa.create_engine(
271
285
  system_db_url,
272
- pool_size=pool_size,
273
- max_overflow=0,
274
- pool_timeout=30,
275
- connect_args={"connect_timeout": 10},
286
+ **engine_kwargs,
276
287
  )
277
288
 
278
289
  # Run a schema migration for the system database
@@ -378,7 +389,6 @@ class SystemDatabase:
378
389
  cmd = cmd.returning(SystemSchema.workflow_status.c.recovery_attempts, SystemSchema.workflow_status.c.status, SystemSchema.workflow_status.c.workflow_deadline_epoch_ms, SystemSchema.workflow_status.c.name, SystemSchema.workflow_status.c.class_name, SystemSchema.workflow_status.c.config_name, SystemSchema.workflow_status.c.queue_name) # type: ignore
379
390
 
380
391
  results = conn.execute(cmd)
381
-
382
392
  row = results.fetchone()
383
393
  if row is not None:
384
394
  # Check the started workflow matches the expected name, class_name, config_name, and queue_name
@@ -3,8 +3,10 @@ from typing import TYPE_CHECKING, Optional
3
3
 
4
4
  from opentelemetry import trace
5
5
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
6
+ from opentelemetry.sdk.resources import Resource
6
7
  from opentelemetry.sdk.trace import TracerProvider
7
8
  from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
9
+ from opentelemetry.semconv.resource import ResourceAttributes
8
10
  from opentelemetry.trace import Span
9
11
 
10
12
  from dbos._utils import GlobalParams
@@ -23,7 +25,13 @@ class DBOSTracer:
23
25
 
24
26
  def config(self, config: ConfigFile) -> None:
25
27
  if not isinstance(trace.get_tracer_provider(), TracerProvider):
26
- provider = TracerProvider()
28
+ resource = Resource(
29
+ attributes={
30
+ ResourceAttributes.SERVICE_NAME: config["name"],
31
+ }
32
+ )
33
+
34
+ provider = TracerProvider(resource=resource)
27
35
  if os.environ.get("DBOS__CONSOLE_TRACES", None) is not None:
28
36
  processor = BatchSpanProcessor(ConsoleSpanExporter())
29
37
  provider.add_span_processor(processor)
@@ -28,7 +28,7 @@ dependencies = [
28
28
  ]
29
29
  requires-python = ">=3.9"
30
30
  readme = "README.md"
31
- version = "0.26.0a25"
31
+ version = "0.27.0a2"
32
32
 
33
33
  [project.license]
34
34
  text = "MIT"
@@ -1251,6 +1251,8 @@ def test_configured_pool_sizes():
1251
1251
  dbos.launch()
1252
1252
  assert dbos._app_db.engine.pool._pool.maxsize == 42
1253
1253
  assert dbos._sys_db.engine.pool._pool.maxsize == 43
1254
+ assert dbos._app_db.engine.pool._pre_ping == False
1255
+ assert dbos._sys_db.engine.pool._pre_ping == False
1254
1256
  dbos.destroy()
1255
1257
 
1256
1258
 
@@ -1326,3 +1328,21 @@ def test_get_dbos_database_url(mocker):
1326
1328
  database="some_db",
1327
1329
  ).render_as_string(hide_password=False)
1328
1330
  assert get_dbos_database_url() == expected_url
1331
+
1332
+
1333
+ def test_db_engine_kwargs():
1334
+ config: DBOSConfig = {
1335
+ "name": "test-app",
1336
+ "db_engine_kwargs": {
1337
+ "pool_pre_ping": True,
1338
+ },
1339
+ }
1340
+
1341
+ dbos = DBOS(config=config)
1342
+ dbos.launch()
1343
+ assert dbos._app_db.engine.pool._pre_ping == True
1344
+ assert dbos._sys_db.engine.pool._pre_ping == True
1345
+ # Default values should be set
1346
+ assert dbos._app_db.engine.pool._pool.maxsize == 20
1347
+ assert dbos._sys_db.engine.pool._pool.maxsize == 20
1348
+ dbos.destroy()
@@ -17,6 +17,10 @@ def test_spans(dbos: DBOS) -> None:
17
17
  @DBOS.workflow()
18
18
  def test_workflow() -> None:
19
19
  test_step()
20
+ current_span = DBOS.span
21
+ subspan = DBOS.tracer.start_span({"name": "a new span"}, parent=current_span)
22
+ subspan.add_event("greeting_event", {"name": "a new event"})
23
+ DBOS.tracer.end_span(subspan)
20
24
 
21
25
  @DBOS.step()
22
26
  def test_step() -> None:
@@ -33,20 +37,23 @@ def test_spans(dbos: DBOS) -> None:
33
37
 
34
38
  spans = exporter.get_finished_spans()
35
39
 
36
- assert len(spans) == 3
40
+ assert len(spans) == 4
37
41
 
38
42
  for span in spans:
39
43
  assert span.attributes is not None
40
44
  assert span.attributes["applicationVersion"] == GlobalParams.app_version
45
+ assert span.attributes["executorID"] == GlobalParams.executor_id
41
46
  assert span.context is not None
42
47
 
43
48
  assert spans[0].name == test_step.__name__
44
- assert spans[1].name == test_workflow.__name__
45
- assert spans[2].name == test_step.__name__
49
+ assert spans[1].name == 'a new span'
50
+ assert spans[2].name == test_workflow.__name__
51
+ assert spans[3].name == test_step.__name__
46
52
 
47
- assert spans[0].parent.span_id == spans[1].context.span_id # type: ignore
48
- assert spans[1].parent == None
53
+ assert spans[0].parent.span_id == spans[2].context.span_id # type: ignore
54
+ assert spans[1].parent.span_id == spans[2].context.span_id # type: ignore
49
55
  assert spans[2].parent == None
56
+ assert spans[3].parent == None
50
57
 
51
58
 
52
59
  @pytest.mark.asyncio
@@ -55,6 +62,10 @@ async def test_spans_async(dbos: DBOS) -> None:
55
62
  @DBOS.workflow()
56
63
  async def test_workflow() -> None:
57
64
  await test_step()
65
+ current_span = DBOS.span
66
+ subspan = DBOS.tracer.start_span({"name": "a new span"}, parent=current_span)
67
+ subspan.add_event("greeting_event", {"name": "a new event"})
68
+ DBOS.tracer.end_span(subspan)
58
69
 
59
70
  @DBOS.step()
60
71
  async def test_step() -> None:
@@ -71,20 +82,23 @@ async def test_spans_async(dbos: DBOS) -> None:
71
82
 
72
83
  spans = exporter.get_finished_spans()
73
84
 
74
- assert len(spans) == 3
85
+ assert len(spans) == 4
75
86
 
76
87
  for span in spans:
77
88
  assert span.attributes is not None
78
89
  assert span.attributes["applicationVersion"] == GlobalParams.app_version
90
+ assert span.attributes["executorID"] == GlobalParams.executor_id
79
91
  assert span.context is not None
80
92
 
81
93
  assert spans[0].name == test_step.__name__
82
- assert spans[1].name == test_workflow.__name__
83
- assert spans[2].name == test_step.__name__
94
+ assert spans[1].name == 'a new span'
95
+ assert spans[2].name == test_workflow.__name__
96
+ assert spans[3].name == test_step.__name__
84
97
 
85
- assert spans[0].parent.span_id == spans[1].context.span_id # type: ignore
86
- assert spans[1].parent == None
98
+ assert spans[0].parent.span_id == spans[2].context.span_id # type: ignore
99
+ assert spans[1].parent.span_id == spans[2].context.span_id # type: ignore
87
100
  assert spans[2].parent == None
101
+ assert spans[3].parent == None
88
102
 
89
103
 
90
104
  def test_temp_wf_fastapi(dbos_fastapi: Tuple[DBOS, FastAPI]) -> 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