@@ -350,6 +350,117 @@ public async Task TaskWithSuborchestration()
350350 } ) ;
351351 }
352352
353+ [ Fact ]
354+ public async Task TaskWithSuborchestrationFailure ( )
355+ {
356+ var activities = new List < Activity > ( ) ;
357+
358+ using var listener = CreateListener ( ActivitySourceNames , activities ) ;
359+
360+ string orchestratorName = nameof ( TaskWithSuborchestrationFailure ) ;
361+ string subOrchestratorName = "SubOrchestration" ;
362+ string activityName = nameof ( TestActivityAsync ) ;
363+
364+ await using HostTestLifetime server = await this . StartWorkerAsync ( b =>
365+ {
366+ b . AddTasks ( tasks => tasks
367+ . AddOrchestratorFunc < bool , bool > (
368+ orchestratorName ,
369+ async ( ctx , input ) =>
370+ {
371+ await ctx . CallSubOrchestratorAsync ( subOrchestratorName , input : false ) ;
372+
373+ return true ;
374+ } )
375+ . AddOrchestratorFunc < bool , bool > (
376+ subOrchestratorName ,
377+ async ( ctx , input ) =>
378+ {
379+ await ctx . CallActivityAsync ( nameof ( TestActivityAsync ) , input ) ;
380+
381+ return true ;
382+ } )
383+ . AddActivityFunc < bool , bool > ( activityName , ( _ , input ) => TestActivityAsync ( input ) ) ) ;
384+ } ) ;
385+
386+ string instanceId ;
387+
388+ using ( var activity = TestActivitySource . StartActivity ( "Test" ) )
389+ {
390+ instanceId = await server . Client . ScheduleNewOrchestrationInstanceAsync ( orchestratorName , input : true , cancellation : this . TimeoutToken ) ;
391+
392+ OrchestrationMetadata metadata = await server . Client . WaitForInstanceCompletionAsync ( instanceId , getInputsAndOutputs : true , this . TimeoutToken ) ;
393+ }
394+
395+ var testActivity = activities . Single ( a => a . Source == TestActivitySource && a . OperationName == "Test" ) ;
396+ var createActivity = activities . Single ( a => a . Source . Name == CoreActivitySourceName && a . OperationName == $ "create_orchestration:{ orchestratorName } ") ;
397+
398+ // The creation activity should be parented to the test activity.
399+ createActivity . ParentId . Should ( ) . Be ( testActivity . Id ) ;
400+ createActivity . ParentSpanId . Should ( ) . Be ( testActivity . SpanId ) ;
401+ createActivity . TagObjects . Should ( ) . ContainKey ( "durabletask.task.instance_id" ) . WhoseValue . Should ( ) . Be ( instanceId ) ;
402+ createActivity . TagObjects . Should ( ) . ContainKey ( "durabletask.task.name" ) . WhoseValue . Should ( ) . Be ( orchestratorName ) ;
403+ createActivity . TagObjects . Should ( ) . ContainKey ( "durabletask.type" ) . WhoseValue . Should ( ) . Be ( "orchestration" ) ;
404+
405+ var orchestrationActivities = activities . Where ( a => a . Source . Name == CoreActivitySourceName && a . OperationName == $ "orchestration:{ orchestratorName } ") . ToList ( ) ;
406+
407+ orchestrationActivities . Should ( ) . HaveCountGreaterThan ( 0 ) ;
408+
409+ // The orchestration activities should be the same "logical" orchestration activity.
410+ orchestrationActivities . Select ( a => a . StartTimeUtc ) . Distinct ( ) . Should ( ) . HaveCount ( 1 ) ;
411+ orchestrationActivities . Select ( a => a . Id ) . Distinct ( ) . Should ( ) . HaveCount ( 1 ) ;
412+ orchestrationActivities . Select ( a => a . SpanId ) . Distinct ( ) . Should ( ) . HaveCount ( 1 ) ;
413+
414+ // The orchestration activities should be parented to the create activity.
415+ orchestrationActivities
416+ . Should ( ) . AllSatisfy ( a =>
417+ {
418+ a . Kind . Should ( ) . Be ( ActivityKind . Server ) ;
419+ a . ParentId . Should ( ) . Be ( createActivity . Id ) ;
420+ a . ParentSpanId . Should ( ) . Be ( createActivity . SpanId ) ;
421+ a . Status . Should ( ) . Be ( ActivityStatusCode . Error ) ;
422+
423+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.task.instance_id" ) . WhoseValue . Should ( ) . Be ( instanceId ) ;
424+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.task.name" ) . WhoseValue . Should ( ) . Be ( orchestratorName ) ;
425+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.type" ) . WhoseValue . Should ( ) . Be ( "orchestration" ) ;
426+ } ) ;
427+
428+ var orchestrationActivity = orchestrationActivities . First ( ) ;
429+
430+ var clientSuborchestrationActivities = activities . Where ( a => a . Kind == ActivityKind . Client && a . Source . Name == CoreActivitySourceName && a . OperationName == $ "orchestration:{ subOrchestratorName } ") . ToList ( ) ;
431+
432+ // The client suborchestration activities should be parented to the orchestration activity.
433+ clientSuborchestrationActivities
434+ . Should ( ) . HaveCount ( 1 )
435+ . And . AllSatisfy ( a =>
436+ {
437+ a . ParentId . Should ( ) . Be ( orchestrationActivity . Id ) ;
438+ a . ParentSpanId . Should ( ) . Be ( orchestrationActivity . SpanId ) ;
439+ a . Status . Should ( ) . Be ( ActivityStatusCode . Error ) ;
440+
441+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.task.instance_id" ) . WhoseValue . Should ( ) . Be ( instanceId ) ;
442+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.task.name" ) . WhoseValue . Should ( ) . Be ( subOrchestratorName ) ;
443+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.type" ) . WhoseValue . Should ( ) . Be ( "orchestration" ) ;
444+ } ) ;
445+
446+ var clientSuborchestrationActivity = clientSuborchestrationActivities . First ( ) ;
447+
448+ var serverSuborchestrationActivities = activities . Where ( a => a . Kind == ActivityKind . Server && a . Source . Name == CoreActivitySourceName && a . OperationName == $ "orchestration:{ subOrchestratorName } ") . ToList ( ) ;
449+
450+ // The server suborchestration activities should be parented to the client orchestration activity.
451+ serverSuborchestrationActivities
452+ . Should ( ) . HaveCountGreaterThan ( 0 )
453+ . And . AllSatisfy ( a =>
454+ {
455+ a . ParentId . Should ( ) . Be ( clientSuborchestrationActivity . Id ) ;
456+ a . ParentSpanId . Should ( ) . Be ( clientSuborchestrationActivity . SpanId ) ;
457+ a . Status . Should ( ) . Be ( ActivityStatusCode . Error ) ;
458+
459+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.task.name" ) . WhoseValue . Should ( ) . Be ( subOrchestratorName ) ;
460+ a . TagObjects . Should ( ) . ContainKey ( "durabletask.type" ) . WhoseValue . Should ( ) . Be ( "orchestration" ) ;
461+ } ) ;
462+ }
463+
353464 [ Fact ]
354465 public async Task TaskOrchestrationWithSentEvent ( )
355466 {
0 commit comments