@@ -31,6 +31,9 @@ public class TaskHubGrpcServer : P.TaskHubSidecarService.TaskHubSidecarServiceBa
3131 readonly TaskHubDispatcherHost dispatcherHost ;
3232 readonly IsConnectedSignal isConnectedSignal = new ( ) ;
3333 readonly SemaphoreSlim sendWorkItemLock = new ( initialCount : 1 ) ;
34+ readonly ConcurrentDictionary < string , List < P . HistoryEvent > > streamingPastEvents = new ( StringComparer . OrdinalIgnoreCase ) ;
35+
36+ volatile bool supportsHistoryStreaming ;
3437
3538 // Initialized when a client connects to this service to receive work-item commands.
3639 IServerStreamWriter < P . WorkItem > ? workerToClientStream ;
@@ -479,6 +482,8 @@ static P.GetInstanceResponse CreateGetInstanceResponse(OrchestrationState state,
479482
480483 public override async Task GetWorkItems ( P . GetWorkItemsRequest request , IServerStreamWriter < P . WorkItem > responseStream , ServerCallContext context )
481484 {
485+ // Record whether the client supports history streaming
486+ this . supportsHistoryStreaming = request . Capabilities . Contains ( P . WorkerCapability . HistoryStreaming ) ;
482487 // Use a lock to mitigate the race condition where we signal the dispatch host to start but haven't
483488 // yet saved a reference to the client response stream.
484489 lock ( this . isConnectedSignal )
@@ -521,6 +526,35 @@ public override async Task GetWorkItems(P.GetWorkItemsRequest request, IServerSt
521526 }
522527 }
523528
529+ public override async Task StreamInstanceHistory ( P . StreamInstanceHistoryRequest request , IServerStreamWriter < P . HistoryChunk > responseStream , ServerCallContext context )
530+ {
531+ if ( this . streamingPastEvents . TryGetValue ( request . InstanceId , out List < P . HistoryEvent > ? pastEvents ) )
532+ {
533+ const int MaxChunkBytes = 256 * 1024 ; // 256KB per chunk to simulate chunked streaming
534+ int currentSize = 0 ;
535+ P . HistoryChunk chunk = new ( ) ;
536+
537+ foreach ( P . HistoryEvent e in pastEvents )
538+ {
539+ int eventSize = e . CalculateSize ( ) ;
540+ if ( currentSize > 0 && currentSize + eventSize > MaxChunkBytes )
541+ {
542+ await responseStream . WriteAsync ( chunk ) ;
543+ chunk = new P . HistoryChunk ( ) ;
544+ currentSize = 0 ;
545+ }
546+
547+ chunk . Events . Add ( e ) ;
548+ currentSize += eventSize ;
549+ }
550+
551+ if ( chunk . Events . Count > 0 )
552+ {
553+ await responseStream . WriteAsync ( chunk ) ;
554+ }
555+ }
556+ }
557+
524558 /// <summary>
525559 /// Invoked by the <see cref="TaskHubDispatcherHost"/> when a work item is available, proxies the call to execute an orchestrator over a gRPC channel.
526560 /// </summary>
@@ -547,16 +581,37 @@ async Task<GrpcOrchestratorExecutionResult> ITaskExecutor.ExecuteOrchestrator(
547581
548582 try
549583 {
584+ var orkRequest = new P . OrchestratorRequest
585+ {
586+ InstanceId = instance . InstanceId ,
587+ ExecutionId = instance . ExecutionId ,
588+ NewEvents = { newEvents . Select ( ProtobufUtils . ToHistoryEventProto ) } ,
589+ OrchestrationTraceContext = orchestrationTraceContext ,
590+ } ;
591+
592+ // Decide whether to stream based on total size of past events (> 1MiB)
593+ List < P . HistoryEvent > protoPastEvents = pastEvents . Select ( ProtobufUtils . ToHistoryEventProto ) . ToList ( ) ;
594+ int totalBytes = 0 ;
595+ foreach ( P . HistoryEvent ev in protoPastEvents )
596+ {
597+ totalBytes += ev . CalculateSize ( ) ;
598+ }
599+
600+ if ( this . supportsHistoryStreaming && totalBytes > ( 1024 ) )
601+ {
602+ orkRequest . RequiresHistoryStreaming = true ;
603+ // Store past events to serve via StreamInstanceHistory
604+ this . streamingPastEvents [ instance . InstanceId ] = protoPastEvents ;
605+ }
606+ else
607+ {
608+ // Embed full history in the work item
609+ orkRequest . PastEvents . AddRange ( protoPastEvents ) ;
610+ }
611+
550612 await this . SendWorkItemToClientAsync ( new P . WorkItem
551613 {
552- OrchestratorRequest = new P . OrchestratorRequest
553- {
554- InstanceId = instance . InstanceId ,
555- ExecutionId = instance . ExecutionId ,
556- NewEvents = { newEvents . Select ( ProtobufUtils . ToHistoryEventProto ) } ,
557- OrchestrationTraceContext = orchestrationTraceContext ,
558- PastEvents = { pastEvents . Select ( ProtobufUtils . ToHistoryEventProto ) } ,
559- }
614+ OrchestratorRequest = orkRequest ,
560615 } ) ;
561616 }
562617 catch
0 commit comments