3636_attrs_by_task : OrderedDict [str , dict [str , Any ]] = OrderedDict ()
3737# Attrs captured when a span starts, so a later registry change cannot alter a span still queued for export.
3838_attrs_by_span : OrderedDict [str , dict [str , Any ]] = OrderedDict ()
39+ # Spans pinned with no attrs live apart so a flood of plain spans cannot evict an eval span's pinned ids.
40+ _plain_spans : OrderedDict [str , None ] = OrderedDict ()
3941_lock = threading .Lock ()
4042
4143
@@ -83,24 +85,29 @@ def _lookup(span: Span) -> dict[str, Any]:
8385def capture_for_span (span : Span ) -> None :
8486 """Pin the span's attrs at start, empty included, so an eval task registered later cannot claim it."""
8587 with _lock :
86- _attrs_by_span [span .id ] = _lookup (span )
87- while len (_attrs_by_span ) > _MAX_TASKS :
88- _attrs_by_span .popitem (last = False )
88+ attrs = _lookup (span )
89+ store : OrderedDict [str , Any ] = _attrs_by_span if attrs else _plain_spans
90+ store [span .id ] = attrs or None
91+ while len (store ) > _MAX_TASKS :
92+ store .popitem (last = False )
8993
9094
9195def release_span (span_id : str ) -> None :
92- if _attrs_by_span :
96+ if _attrs_by_span or _plain_spans :
9397 with _lock :
9498 _attrs_by_span .pop (span_id , None )
99+ _plain_spans .pop (span_id , None )
95100
96101
97102def attrs_for_span (span : Span ) -> dict [str , Any ]:
98103 """Attrs captured at span start, else those of the task found by ``span.task_id`` then ``span.trace_id``."""
99- if not _attrs_by_task and not _attrs_by_span :
104+ if not _attrs_by_task and not _attrs_by_span and not _plain_spans :
100105 return {}
101106 with _lock :
102107 if span .id in _attrs_by_span :
103108 return dict (_attrs_by_span [span .id ])
109+ if span .id in _plain_spans :
110+ return {}
104111 return _lookup (span )
105112
106113
@@ -109,3 +116,4 @@ def clear() -> None:
109116 with _lock :
110117 _attrs_by_task .clear ()
111118 _attrs_by_span .clear ()
119+ _plain_spans .clear ()
0 commit comments