dbos 1.14.0a3__py3-none-any.whl → 1.14.0a5__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/_context.py CHANGED
@@ -215,11 +215,18 @@ class DBOSContext:
215
215
  def end_handler(self, exc_value: Optional[BaseException]) -> None:
216
216
  self._end_span(exc_value)
217
217
 
218
- def get_current_span(self) -> Optional[Span]:
218
+ """ Return the current DBOS span if any. It must be a span created by DBOS."""
219
+
220
+ def get_current_dbos_span(self) -> Optional[Span]:
219
221
  if len(self.context_spans) > 0:
220
222
  return self.context_spans[-1].span
221
223
  return None
222
224
 
225
+ """ Return the current active span if any. It might not be a DBOS span."""
226
+
227
+ def get_current_active_span(self) -> Optional[Span]:
228
+ return dbos_tracer.get_current_span()
229
+
223
230
  def _start_span(self, attributes: TracedAttributes) -> None:
224
231
  if dbos_tracer.disable_otlp:
225
232
  return
@@ -235,7 +242,7 @@ class DBOSContext:
235
242
  attributes["authenticatedUserAssumedRole"] = self.assumed_role
236
243
  span = dbos_tracer.start_span(
237
244
  attributes,
238
- parent=self.context_spans[-1].span if len(self.context_spans) > 0 else None,
245
+ parent=None, # It'll use the current active span as the parent
239
246
  )
240
247
  # Activate the current span
241
248
  cm = use_span(
dbos/_core.py CHANGED
@@ -56,6 +56,7 @@ from ._error import (
56
56
  DBOSWorkflowConflictIDError,
57
57
  DBOSWorkflowFunctionNotFoundError,
58
58
  )
59
+ from ._logger import dbos_logger
59
60
  from ._registrations import (
60
61
  DEFAULT_MAX_RECOVERY_ATTEMPTS,
61
62
  get_config_name,
@@ -96,6 +97,14 @@ F = TypeVar("F", bound=Callable[..., Any])
96
97
  TEMP_SEND_WF_NAME = "<temp>.temp_send_workflow"
97
98
 
98
99
 
100
+ def check_is_in_coroutine() -> bool:
101
+ try:
102
+ asyncio.get_running_loop()
103
+ return True
104
+ except RuntimeError:
105
+ return False
106
+
107
+
99
108
  class WorkflowHandleFuture(Generic[R]):
100
109
 
101
110
  def __init__(self, workflow_id: str, future: Future[R], dbos: "DBOS"):
@@ -828,6 +837,11 @@ def workflow_wrapper(
828
837
  dbos._sys_db.record_get_result(workflow_id, serialized_r, None)
829
838
  return r
830
839
 
840
+ if check_is_in_coroutine() and not inspect.iscoroutinefunction(func):
841
+ dbos_logger.warning(
842
+ f"Sync workflow ({get_dbos_func_name(func)}) shouldn't be invoked from within another async function. Define it as async or use asyncio.to_thread instead."
843
+ )
844
+
831
845
  outcome = (
832
846
  wfOutcome.wrap(init_wf, dbos=dbos)
833
847
  .also(DBOSAssumeRole(rr))
@@ -957,7 +971,7 @@ def decorate_transaction(
957
971
  dbapi_error
958
972
  ) or dbos._app_db._is_serialization_error(dbapi_error):
959
973
  # Retry on serialization failure
960
- span = ctx.get_current_span()
974
+ span = ctx.get_current_dbos_span()
961
975
  if span:
962
976
  span.add_event(
963
977
  "Transaction Failure",
@@ -1009,6 +1023,10 @@ def decorate_transaction(
1009
1023
  assert (
1010
1024
  ctx.is_workflow()
1011
1025
  ), "Transactions must be called from within workflows"
1026
+ if check_is_in_coroutine():
1027
+ dbos_logger.warning(
1028
+ f"Transaction function ({get_dbos_func_name(func)}) shouldn't be invoked from within another async function. Use asyncio.to_thread instead."
1029
+ )
1012
1030
  with DBOSAssumeRole(rr):
1013
1031
  return invoke_tx(*args, **kwargs)
1014
1032
  else:
@@ -1072,7 +1090,7 @@ def decorate_step(
1072
1090
  exc_info=error,
1073
1091
  )
1074
1092
  ctx = assert_current_dbos_context()
1075
- span = ctx.get_current_span()
1093
+ span = ctx.get_current_dbos_span()
1076
1094
  if span:
1077
1095
  span.add_event(
1078
1096
  f"Step attempt {attempt} failed",
@@ -1153,6 +1171,10 @@ def decorate_step(
1153
1171
 
1154
1172
  @wraps(func)
1155
1173
  def wrapper(*args: Any, **kwargs: Any) -> Any:
1174
+ if check_is_in_coroutine() and not inspect.iscoroutinefunction(func):
1175
+ dbos_logger.warning(
1176
+ f"Sync step ({get_dbos_func_name(func)}) shouldn't be invoked from within another async function. Define it as async or use asyncio.to_thread instead."
1177
+ )
1156
1178
  # If the step is called from a workflow, run it as a step.
1157
1179
  # Otherwise, run it as a normal function.
1158
1180
  ctx = get_local_dbos_context()
dbos/_dbos.py CHANGED
@@ -1297,7 +1297,7 @@ class DBOS:
1297
1297
  def span(cls) -> Span:
1298
1298
  """Return the tracing `Span` associated with the current context."""
1299
1299
  ctx = assert_current_dbos_context()
1300
- span = ctx.get_current_span()
1300
+ span = ctx.get_current_active_span()
1301
1301
  assert span
1302
1302
  return span
1303
1303
 
dbos/_logger.py CHANGED
@@ -39,7 +39,7 @@ class DBOSLogTransformer(logging.Filter):
39
39
  if ctx:
40
40
  if ctx.is_within_workflow():
41
41
  record.operationUUID = ctx.workflow_id
42
- span = ctx.get_current_span()
42
+ span = ctx.get_current_active_span()
43
43
  if span:
44
44
  trace_id = format_trace_id(span.get_span_context().trace_id)
45
45
  record.traceId = trace_id
dbos/_tracer.py CHANGED
@@ -77,5 +77,12 @@ class DBOSTracer:
77
77
  def end_span(self, span: Span) -> None:
78
78
  span.end()
79
79
 
80
+ def get_current_span(self) -> Optional[Span]:
81
+ # Return the current active span if any. It might not be a DBOS span.
82
+ span = trace.get_current_span()
83
+ if span.get_span_context().is_valid:
84
+ return span
85
+ return None
86
+
80
87
 
81
88
  dbos_tracer = DBOSTracer()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dbos
3
- Version: 1.14.0a3
3
+ Version: 1.14.0a5
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-1.14.0a3.dist-info/METADATA,sha256=ZOKRfAWkrYZnIaDxG7NDi3ALPULMzpnSeXKMTMowA8E,13268
2
- dbos-1.14.0a3.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- dbos-1.14.0a3.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
4
- dbos-1.14.0a3.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
1
+ dbos-1.14.0a5.dist-info/METADATA,sha256=TDRJ02P3spTH9e3UKquTU4V0fhr2Hoq7i_yWosvisGM,13268
2
+ dbos-1.14.0a5.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ dbos-1.14.0a5.dist-info/entry_points.txt,sha256=_QOQ3tVfEjtjBlr1jS4sHqHya9lI2aIEIWkz8dqYp14,58
4
+ dbos-1.14.0a5.dist-info/licenses/LICENSE,sha256=VGZit_a5-kdw9WT6fY5jxAWVwGQzgLFyPWrcVVUhVNU,1067
5
5
  dbos/__init__.py,sha256=NssPCubaBxdiKarOWa-wViz1hdJSkmBGcpLX_gQ4NeA,891
6
6
  dbos/__main__.py,sha256=G7Exn-MhGrVJVDbgNlpzhfh8WMX_72t3_oJaFT9Lmt8,653
7
7
  dbos/_admin_server.py,sha256=e8ELhcDWqR3_PNobnNgUvLGh5lzZq0yFSF6dvtzoQRI,16267
@@ -27,10 +27,10 @@ dbos/_classproperty.py,sha256=f0X-_BySzn3yFDRKB2JpCbLYQ9tLwt1XftfshvY7CBs,626
27
27
  dbos/_client.py,sha256=_3Wc2QQc5VDcBuJ3cNb-lWg439OuITo2ex4Y7qb9l44,18800
28
28
  dbos/_conductor/conductor.py,sha256=3E_hL3c9g9yWqKZkvI6KA0-ZzPMPRo06TOzT1esMiek,24114
29
29
  dbos/_conductor/protocol.py,sha256=q3rgLxINFtWFigdOONc-4gX4vn66UmMlJQD6Kj8LnL4,7420
30
- dbos/_context.py,sha256=IMboNgbCqTxfIORqeifE3da-Ce5siMz7MYMLPk5M-AQ,26851
31
- dbos/_core.py,sha256=CG2z5V0xZ-5_2E4NXqGIVdb5bWoN_l_cGswk7diB6RU,48805
30
+ dbos/_context.py,sha256=fzozSsccFVwjtrJVXOfYBA0_x1S21RvvCTyN-VM644g,27111
31
+ dbos/_core.py,sha256=0F1rNYTYLh3kjZB_APh38fblSaKev-2tG8G-9D0rxms,49876
32
32
  dbos/_croniter.py,sha256=XHAyUyibs_59sJQfSNWkP7rqQY6_XrlfuuCxk4jYqek,47559
33
- dbos/_dbos.py,sha256=wKLN7W1ej6cyEOHnCtt3-awnU6SR6MQAlOvTTt5_N-E,58219
33
+ dbos/_dbos.py,sha256=ftbVR5wAHSnc_PXpecVC1ZylY6c8UyiZRpcT2kSO8NQ,58226
34
34
  dbos/_dbos_config.py,sha256=_26ktif8qAZW4Ujg6dZfLkYO7dE4CI8b3IQbw_5YkpA,25710
35
35
  dbos/_debug.py,sha256=99j2SChWmCPAlZoDmjsJGe77tpU2LEa8E2TtLAnnh7o,1831
36
36
  dbos/_docker_pg_helper.py,sha256=tLJXWqZ4S-ExcaPnxg_i6cVxL6ZxrYlZjaGsklY-s2I,6115
@@ -40,7 +40,7 @@ dbos/_fastapi.py,sha256=D0H6TPYYTJ0LnkKn7t9sfPwPgDx6fO8AZQtvBcH3ibI,3277
40
40
  dbos/_flask.py,sha256=Npnakt-a3W5OykONFRkDRnumaDhTQmA0NPdUCGRYKXE,1652
41
41
  dbos/_kafka.py,sha256=Gm4fHWl7gYb-i5BMvwNwm5Km3z8zQpseqdMgqgFjlGI,4252
42
42
  dbos/_kafka_message.py,sha256=NYvOXNG3Qn7bghn1pv3fg4Pbs86ILZGcK4IB-MLUNu0,409
43
- dbos/_logger.py,sha256=vvBL4kzJWBPtfcHIuL0nJAq5cgpeo_D3IiIUDicWLOg,4732
43
+ dbos/_logger.py,sha256=iS4AviQViSKiz-IYCjZLWmW9x616IA-Ms9Xtwq1dcx4,4739
44
44
  dbos/_migration.py,sha256=wJrSTYerlkYDFYmkTqo4a7n4WaKmqXh8BdkUEzgSEQQ,10898
45
45
  dbos/_outcome.py,sha256=7HvosMfEHTh1U5P6xok7kFTGLwa2lPaul0YApb3UnN4,8191
46
46
  dbos/_queue.py,sha256=0kJTPwXy3nZ4Epzt-lHky9M9S4L31645drPGFR8fIJY,4854
@@ -65,7 +65,7 @@ dbos/_templates/dbos-db-starter/migrations/env.py.dbos,sha256=IBB_gz9RjC20HPfOTG
65
65
  dbos/_templates/dbos-db-starter/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
66
66
  dbos/_templates/dbos-db-starter/migrations/versions/2024_07_31_180642_init.py,sha256=MpS7LGaJS0CpvsjhfDkp9EJqvMvVCjRPfUp4c0aE2ys,941
67
67
  dbos/_templates/dbos-db-starter/start_postgres_docker.py,sha256=lQVLlYO5YkhGPEgPqwGc7Y8uDKse9HsWv5fynJEFJHM,1681
68
- dbos/_tracer.py,sha256=8aOAVTBnj2q9DcOb5KJCfo56CVZ1ZvsWBscaNlIX-7k,3150
68
+ dbos/_tracer.py,sha256=1MtRa0bS3ZfpZN3dw-O57_M1lc76WYK2bAThLWW2TSc,3408
69
69
  dbos/_utils.py,sha256=ZdoM1MDbHnlJrh31zfhp3iX62bAxK1kyvMwXnltC_84,1779
70
70
  dbos/_workflow_commands.py,sha256=EmmAaQfRWeOZm_WPTznuU-O3he3jiSzzT9VpYrhxugE,4835
71
71
  dbos/cli/_github_init.py,sha256=Y_bDF9gfO2jB1id4FV5h1oIxEJRWyqVjhb7bNEa5nQ0,3224
@@ -75,4 +75,4 @@ dbos/cli/migration.py,sha256=5GiyagLZkyVvDz3StYxtFdkFoKFCmh6eSXjzsIGhZ_A,3330
75
75
  dbos/dbos-config.schema.json,sha256=LyUT1DOTaAwOP6suxQGS5KemVIqXGPyu_q7Hbo0neA8,6192
76
76
  dbos/py.typed,sha256=QfzXT1Ktfk3Rj84akygc7_42z0lRpCq0Ilh8OXI6Zas,44
77
77
  version/__init__.py,sha256=L4sNxecRuqdtSFdpUGX3TtBi9KL3k7YsZVIvv-fv9-A,1678
78
- dbos-1.14.0a3.dist-info/RECORD,,
78
+ dbos-1.14.0a5.dist-info/RECORD,,