@@ -567,6 +567,69 @@ async def test_otel_tracing_workflow_failure(
567567 ), f"Span hierarchy mismatch.\n Expected:\n { expected_hierarchy } \n Actual:\n { actual_hierarchy } "
568568
569569
570+ async def test_otel_standalone_activity_tracing (
571+ client : Client ,
572+ env : WorkflowEnvironment ,
573+ reset_otel_tracer_provider : Any , # type: ignore[reportUnusedParameter]
574+ ):
575+ if env .supports_time_skipping :
576+ pytest .skip (
577+ "Java test server: https://github.com/temporalio/sdk-java/issues/2741"
578+ )
579+ exporter = InMemorySpanExporter ()
580+ provider = create_tracer_provider ()
581+ provider .add_span_processor (SimpleSpanProcessor (exporter ))
582+ opentelemetry .trace .set_tracer_provider (provider )
583+
584+ new_config = client .config ()
585+ new_config ["plugins" ] = [OpenTelemetryPlugin (add_temporal_spans = True )]
586+ new_client = Client (** new_config )
587+
588+ async with new_worker (
589+ new_client ,
590+ activities = [simple_no_context_activity ],
591+ ) as worker :
592+ handle = await new_client .start_activity (
593+ simple_no_context_activity ,
594+ id = f"activity_{ uuid .uuid4 ()} " ,
595+ task_queue = worker .task_queue ,
596+ schedule_to_close_timeout = timedelta (seconds = 10 ),
597+ )
598+ await handle .result ()
599+
600+ # Use a queue with no worker so activities stay in SCHEDULED state,
601+ # allowing describe/cancel/terminate to be called without a race.
602+ no_worker_queue = f"task_queue_{ uuid .uuid4 ()} "
603+
604+ cancel_handle = await new_client .start_activity (
605+ simple_no_context_activity ,
606+ id = f"activity_{ uuid .uuid4 ()} " ,
607+ task_queue = no_worker_queue ,
608+ schedule_to_close_timeout = timedelta (seconds = 30 ),
609+ )
610+ await cancel_handle .describe ()
611+ await cancel_handle .cancel ()
612+
613+ terminate_handle = await new_client .start_activity (
614+ simple_no_context_activity ,
615+ id = f"activity_{ uuid .uuid4 ()} " ,
616+ task_queue = no_worker_queue ,
617+ schedule_to_close_timeout = timedelta (seconds = 30 ),
618+ )
619+ await terminate_handle .terminate ()
620+
621+ assert dump_spans (exporter .get_finished_spans (), with_attributes = False ) == [
622+ "StartActivity:simple_no_context_activity" ,
623+ " RunActivity:simple_no_context_activity" ,
624+ " Activity" ,
625+ "StartActivity:simple_no_context_activity" ,
626+ "DescribeActivity" ,
627+ "CancelActivity" ,
628+ "StartActivity:simple_no_context_activity" ,
629+ "TerminateActivity" ,
630+ ]
631+
632+
570633def test_replay_safe_span_delegates_extra_attributes ():
571634 """Test that _ReplaySafeSpan delegates attribute access to the underlying span.
572635
0 commit comments