@@ -251,3 +251,40 @@ async def test_a_run_flushes_processors_in_pipeline_order():
251251 await exporter .create_isolated_instance (ContextState ())._cleanup ()
252252
253253 assert events [:4 ] == ["upstream start" , "upstream end" , "downstream start" , "downstream end" ]
254+
255+
256+ async def test_spans_still_on_their_way_when_the_builder_exits_are_exported (monkeypatch ):
257+ """The builder's exit drains the batcher its per-run copies shared, even though the original never started."""
258+ from nat .observability .exporter import processing_exporter
259+
260+ monkeypatch .setattr (processing_exporter , "_RUN_END_WAIT_SECONDS" , 0.05 )
261+ config = Config .model_validate ({
262+ "general" : {
263+ "telemetry" : {
264+ "tracing" : {
265+ "recording" : {
266+ "_type" : "batching_test_otel" , "slow_first_processor" : True , "slow_processor_delay" : 0.3
267+ }
268+ }
269+ }
270+ },
271+ "functions" : {
272+ "tool" : {
273+ "_type" : "batching_test_tool"
274+ }
275+ },
276+ "workflow" : {
277+ "_type" : "batching_test_workflow"
278+ },
279+ })
280+ async with WorkflowBuilder .from_config (config = config ) as builder :
281+ session_manager = await SessionManager .create (config = config , shared_builder = builder , max_concurrency = 1 )
282+ try :
283+ async with session_manager .session () as session :
284+ async with session .run ("hi" ) as runner :
285+ assert await runner .result (to_type = str ) == "hi"
286+ finally :
287+ await session_manager .shutdown ()
288+ await asyncio .sleep (0.6 ) # the late spans reach the batcher after the builder has closed
289+
290+ assert sum (EXPORT_CALLS ) == SPANS_PER_RUN
0 commit comments