diff --git a/Directory.Packages.props b/Directory.Packages.props
index b2b1ff2ed..5745a27d3 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -15,9 +15,9 @@
-
-
-
+
+
+
@@ -29,8 +29,8 @@
-
-
+
+
@@ -68,7 +68,7 @@
-
+
diff --git a/src/WebJobs.Extensions.DurableTask/Grpc/Protos/orchestrator_service.proto b/src/WebJobs.Extensions.DurableTask/Grpc/Protos/orchestrator_service.proto
index df5143bc9..c8b55430d 100644
--- a/src/WebJobs.Extensions.DurableTask/Grpc/Protos/orchestrator_service.proto
+++ b/src/WebJobs.Extensions.DurableTask/Grpc/Protos/orchestrator_service.proto
@@ -1,821 +1,828 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-syntax = "proto3";
-
-option csharp_namespace = "Microsoft.DurableTask.Protobuf";
-option java_package = "com.microsoft.durabletask.implementation.protobuf";
-option go_package = "/internal/protos";
-
-import "google/protobuf/timestamp.proto";
-import "google/protobuf/duration.proto";
-import "google/protobuf/wrappers.proto";
-import "google/protobuf/empty.proto";
-import "google/protobuf/struct.proto";
-
-message OrchestrationInstance {
- string instanceId = 1;
- google.protobuf.StringValue executionId = 2;
-}
-
-message ActivityRequest {
- string name = 1;
- google.protobuf.StringValue version = 2;
- google.protobuf.StringValue input = 3;
- OrchestrationInstance orchestrationInstance = 4;
- int32 taskId = 5;
- TraceContext parentTraceContext = 6;
-}
-
-message ActivityResponse {
- string instanceId = 1;
- int32 taskId = 2;
- google.protobuf.StringValue result = 3;
- TaskFailureDetails failureDetails = 4;
- string completionToken = 5;
-}
-
-message TaskFailureDetails {
- string errorType = 1;
- string errorMessage = 2;
- google.protobuf.StringValue stackTrace = 3;
- TaskFailureDetails innerFailure = 4;
- bool isNonRetriable = 5;
-}
-
-enum OrchestrationStatus {
- ORCHESTRATION_STATUS_RUNNING = 0;
- ORCHESTRATION_STATUS_COMPLETED = 1;
- ORCHESTRATION_STATUS_CONTINUED_AS_NEW = 2;
- ORCHESTRATION_STATUS_FAILED = 3;
- ORCHESTRATION_STATUS_CANCELED = 4;
- ORCHESTRATION_STATUS_TERMINATED = 5;
- ORCHESTRATION_STATUS_PENDING = 6;
- ORCHESTRATION_STATUS_SUSPENDED = 7;
-}
-
-message ParentInstanceInfo {
- int32 taskScheduledId = 1;
- google.protobuf.StringValue name = 2;
- google.protobuf.StringValue version = 3;
- OrchestrationInstance orchestrationInstance = 4;
-}
-
-message TraceContext {
- string traceParent = 1;
- string spanID = 2 [deprecated=true];
- google.protobuf.StringValue traceState = 3;
-}
-
-message ExecutionStartedEvent {
- string name = 1;
- google.protobuf.StringValue version = 2;
- google.protobuf.StringValue input = 3;
- OrchestrationInstance orchestrationInstance = 4;
- ParentInstanceInfo parentInstance = 5;
- google.protobuf.Timestamp scheduledStartTimestamp = 6;
- TraceContext parentTraceContext = 7;
- google.protobuf.StringValue orchestrationSpanID = 8;
- map tags = 9;
-}
-
-message ExecutionCompletedEvent {
- OrchestrationStatus orchestrationStatus = 1;
- google.protobuf.StringValue result = 2;
- TaskFailureDetails failureDetails = 3;
-}
-
-message ExecutionTerminatedEvent {
- google.protobuf.StringValue input = 1;
- bool recurse = 2;
-}
-
-message TaskScheduledEvent {
- string name = 1;
- google.protobuf.StringValue version = 2;
- google.protobuf.StringValue input = 3;
- TraceContext parentTraceContext = 4;
- map tags = 5;
-}
-
-message TaskCompletedEvent {
- int32 taskScheduledId = 1;
- google.protobuf.StringValue result = 2;
-}
-
-message TaskFailedEvent {
- int32 taskScheduledId = 1;
- TaskFailureDetails failureDetails = 2;
-}
-
-message SubOrchestrationInstanceCreatedEvent {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue version = 3;
- google.protobuf.StringValue input = 4;
- TraceContext parentTraceContext = 5;
-}
-
-message SubOrchestrationInstanceCompletedEvent {
- int32 taskScheduledId = 1;
- google.protobuf.StringValue result = 2;
-}
-
-message SubOrchestrationInstanceFailedEvent {
- int32 taskScheduledId = 1;
- TaskFailureDetails failureDetails = 2;
-}
-
-message TimerCreatedEvent {
- google.protobuf.Timestamp fireAt = 1;
-}
-
-message TimerFiredEvent {
- google.protobuf.Timestamp fireAt = 1;
- int32 timerId = 2;
-}
-
-message OrchestratorStartedEvent {
- // No payload data
-}
-
-message OrchestratorCompletedEvent {
- // No payload data
-}
-
-message EventSentEvent {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue input = 3;
-}
-
-message EventRaisedEvent {
- string name = 1;
- google.protobuf.StringValue input = 2;
-}
-
-message GenericEvent {
- google.protobuf.StringValue data = 1;
-}
-
-message HistoryStateEvent {
- OrchestrationState orchestrationState = 1;
-}
-
-message ContinueAsNewEvent {
- google.protobuf.StringValue input = 1;
-}
-
-message ExecutionSuspendedEvent {
- google.protobuf.StringValue input = 1;
-}
-
-message ExecutionResumedEvent {
- google.protobuf.StringValue input = 1;
-}
-
-message EntityOperationSignaledEvent {
- string requestId = 1;
- string operation = 2;
- google.protobuf.Timestamp scheduledTime = 3;
- google.protobuf.StringValue input = 4;
- google.protobuf.StringValue targetInstanceId = 5; // used only within histories, null in messages
-}
-
-message EntityOperationCalledEvent {
- string requestId = 1;
- string operation = 2;
- google.protobuf.Timestamp scheduledTime = 3;
- google.protobuf.StringValue input = 4;
- google.protobuf.StringValue parentInstanceId = 5; // used only within messages, null in histories
- google.protobuf.StringValue parentExecutionId = 6; // used only within messages, null in histories
- google.protobuf.StringValue targetInstanceId = 7; // used only within histories, null in messages
-}
-
-message EntityLockRequestedEvent {
- string criticalSectionId = 1;
- repeated string lockSet = 2;
- int32 position = 3;
- google.protobuf.StringValue parentInstanceId = 4; // used only within messages, null in histories
-}
-
-message EntityOperationCompletedEvent {
- string requestId = 1;
- google.protobuf.StringValue output = 2;
-}
-
-message EntityOperationFailedEvent {
- string requestId = 1;
- TaskFailureDetails failureDetails = 2;
-}
-
-message EntityUnlockSentEvent {
- string criticalSectionId = 1;
- google.protobuf.StringValue parentInstanceId = 2; // used only within messages, null in histories
- google.protobuf.StringValue targetInstanceId = 3; // used only within histories, null in messages
-}
-
-message EntityLockGrantedEvent {
- string criticalSectionId = 1;
-}
-
-message HistoryEvent {
- int32 eventId = 1;
- google.protobuf.Timestamp timestamp = 2;
- oneof eventType {
- ExecutionStartedEvent executionStarted = 3;
- ExecutionCompletedEvent executionCompleted = 4;
- ExecutionTerminatedEvent executionTerminated = 5;
- TaskScheduledEvent taskScheduled = 6;
- TaskCompletedEvent taskCompleted = 7;
- TaskFailedEvent taskFailed = 8;
- SubOrchestrationInstanceCreatedEvent subOrchestrationInstanceCreated = 9;
- SubOrchestrationInstanceCompletedEvent subOrchestrationInstanceCompleted = 10;
- SubOrchestrationInstanceFailedEvent subOrchestrationInstanceFailed = 11;
- TimerCreatedEvent timerCreated = 12;
- TimerFiredEvent timerFired = 13;
- OrchestratorStartedEvent orchestratorStarted = 14;
- OrchestratorCompletedEvent orchestratorCompleted = 15;
- EventSentEvent eventSent = 16;
- EventRaisedEvent eventRaised = 17;
- GenericEvent genericEvent = 18;
- HistoryStateEvent historyState = 19;
- ContinueAsNewEvent continueAsNew = 20;
- ExecutionSuspendedEvent executionSuspended = 21;
- ExecutionResumedEvent executionResumed = 22;
- EntityOperationSignaledEvent entityOperationSignaled = 23;
- EntityOperationCalledEvent entityOperationCalled = 24;
- EntityOperationCompletedEvent entityOperationCompleted = 25;
- EntityOperationFailedEvent entityOperationFailed = 26;
- EntityLockRequestedEvent entityLockRequested = 27;
- EntityLockGrantedEvent entityLockGranted = 28;
- EntityUnlockSentEvent entityUnlockSent = 29;
- }
-}
-
-message ScheduleTaskAction {
- string name = 1;
- google.protobuf.StringValue version = 2;
- google.protobuf.StringValue input = 3;
- map tags = 4;
- TraceContext parentTraceContext = 5;
-}
-
-message CreateSubOrchestrationAction {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue version = 3;
- google.protobuf.StringValue input = 4;
- TraceContext parentTraceContext = 5;
-}
-
-message CreateTimerAction {
- google.protobuf.Timestamp fireAt = 1;
-}
-
-message SendEventAction {
- OrchestrationInstance instance = 1;
- string name = 2;
- google.protobuf.StringValue data = 3;
-}
-
-message CompleteOrchestrationAction {
- OrchestrationStatus orchestrationStatus = 1;
- google.protobuf.StringValue result = 2;
- google.protobuf.StringValue details = 3;
- google.protobuf.StringValue newVersion = 4;
- repeated HistoryEvent carryoverEvents = 5;
- TaskFailureDetails failureDetails = 6;
-}
-
-message TerminateOrchestrationAction {
- string instanceId = 1;
- google.protobuf.StringValue reason = 2;
- bool recurse = 3;
-}
-
-message SendEntityMessageAction {
- oneof EntityMessageType {
- EntityOperationSignaledEvent entityOperationSignaled = 1;
- EntityOperationCalledEvent entityOperationCalled = 2;
- EntityLockRequestedEvent entityLockRequested = 3;
- EntityUnlockSentEvent entityUnlockSent = 4;
- }
-}
-
-message OrchestratorAction {
- int32 id = 1;
- oneof orchestratorActionType {
- ScheduleTaskAction scheduleTask = 2;
- CreateSubOrchestrationAction createSubOrchestration = 3;
- CreateTimerAction createTimer = 4;
- SendEventAction sendEvent = 5;
- CompleteOrchestrationAction completeOrchestration = 6;
- TerminateOrchestrationAction terminateOrchestration = 7;
- SendEntityMessageAction sendEntityMessage = 8;
- }
-}
-
-message OrchestrationTraceContext {
- google.protobuf.StringValue spanID = 1;
- google.protobuf.Timestamp spanStartTime = 2;
-}
-
-message OrchestratorRequest {
- string instanceId = 1;
- google.protobuf.StringValue executionId = 2;
- repeated HistoryEvent pastEvents = 3;
- repeated HistoryEvent newEvents = 4;
- OrchestratorEntityParameters entityParameters = 5;
- bool requiresHistoryStreaming = 6;
- map properties = 7;
-
- OrchestrationTraceContext orchestrationTraceContext = 8;
-}
-
-message OrchestratorResponse {
- string instanceId = 1;
- repeated OrchestratorAction actions = 2;
- google.protobuf.StringValue customStatus = 3;
- string completionToken = 4;
-
- // The number of work item events that were processed by the orchestrator.
- // This field is optional. If not set, the service should assume that the orchestrator processed all events.
- google.protobuf.Int32Value numEventsProcessed = 5;
- OrchestrationTraceContext orchestrationTraceContext = 6;
-
- // Whether or not a history is required to complete the original OrchestratorRequest and none was provided.
- bool requiresHistory = 7;
-}
-
-message CreateInstanceRequest {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue version = 3;
- google.protobuf.StringValue input = 4;
- google.protobuf.Timestamp scheduledStartTimestamp = 5;
- OrchestrationIdReusePolicy orchestrationIdReusePolicy = 6;
- google.protobuf.StringValue executionId = 7;
- map tags = 8;
- TraceContext parentTraceContext = 9;
- google.protobuf.Timestamp requestTime = 10;
-}
-
-message OrchestrationIdReusePolicy {
- repeated OrchestrationStatus replaceableStatus = 1;
- reserved 2;
-}
-
-message CreateInstanceResponse {
- string instanceId = 1;
-}
-
-message GetInstanceRequest {
- string instanceId = 1;
- bool getInputsAndOutputs = 2;
-}
-
-message GetInstanceResponse {
- bool exists = 1;
- OrchestrationState orchestrationState = 2;
-}
-
-message RewindInstanceRequest {
- string instanceId = 1;
- google.protobuf.StringValue reason = 2;
-}
-
-message RewindInstanceResponse {
- // Empty for now. Using explicit type incase we want to add content later.
-}
-
-message OrchestrationState {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue version = 3;
- OrchestrationStatus orchestrationStatus = 4;
- google.protobuf.Timestamp scheduledStartTimestamp = 5;
- google.protobuf.Timestamp createdTimestamp = 6;
- google.protobuf.Timestamp lastUpdatedTimestamp = 7;
- google.protobuf.StringValue input = 8;
- google.protobuf.StringValue output = 9;
- google.protobuf.StringValue customStatus = 10;
- TaskFailureDetails failureDetails = 11;
- google.protobuf.StringValue executionId = 12;
- google.protobuf.Timestamp completedTimestamp = 13;
- google.protobuf.StringValue parentInstanceId = 14;
- map tags = 15;
-}
-
-message RaiseEventRequest {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue input = 3;
-}
-
-message RaiseEventResponse {
- // No payload
-}
-
-message TerminateRequest {
- string instanceId = 1;
- google.protobuf.StringValue output = 2;
- bool recursive = 3;
-}
-
-message TerminateResponse {
- // No payload
-}
-
-message SuspendRequest {
- string instanceId = 1;
- google.protobuf.StringValue reason = 2;
-}
-
-message SuspendResponse {
- // No payload
-}
-
-message ResumeRequest {
- string instanceId = 1;
- google.protobuf.StringValue reason = 2;
-}
-
-message ResumeResponse {
- // No payload
-}
-
-message QueryInstancesRequest {
- InstanceQuery query = 1;
-}
-
-message InstanceQuery{
- repeated OrchestrationStatus runtimeStatus = 1;
- google.protobuf.Timestamp createdTimeFrom = 2;
- google.protobuf.Timestamp createdTimeTo = 3;
- repeated google.protobuf.StringValue taskHubNames = 4;
- int32 maxInstanceCount = 5;
- google.protobuf.StringValue continuationToken = 6;
- google.protobuf.StringValue instanceIdPrefix = 7;
- bool fetchInputsAndOutputs = 8;
-}
-
-message QueryInstancesResponse {
- repeated OrchestrationState orchestrationState = 1;
- google.protobuf.StringValue continuationToken = 2;
-}
-
-message PurgeInstancesRequest {
- oneof request {
- string instanceId = 1;
- PurgeInstanceFilter purgeInstanceFilter = 2;
- }
- bool recursive = 3;
-}
-
-message PurgeInstanceFilter {
- google.protobuf.Timestamp createdTimeFrom = 1;
- google.protobuf.Timestamp createdTimeTo = 2;
- repeated OrchestrationStatus runtimeStatus = 3;
-}
-
-message PurgeInstancesResponse {
- int32 deletedInstanceCount = 1;
- google.protobuf.BoolValue isComplete = 2;
-}
-
-message RestartInstanceRequest {
- string instanceId = 1;
- bool restartWithNewInstanceId = 2;
-}
-
-message RestartInstanceResponse {
- string instanceId = 1;
-}
-
-message CreateTaskHubRequest {
- bool recreateIfExists = 1;
-}
-
-message CreateTaskHubResponse {
- //no playload
-}
-
-message DeleteTaskHubRequest {
- //no playload
-}
-
-message DeleteTaskHubResponse {
- //no playload
-}
-
-message SignalEntityRequest {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue input = 3;
- string requestId = 4;
- google.protobuf.Timestamp scheduledTime = 5;
- TraceContext parentTraceContext = 6;
- google.protobuf.Timestamp requestTime = 7;
-}
-
-message SignalEntityResponse {
- // no payload
-}
-
-message GetEntityRequest {
- string instanceId = 1;
- bool includeState = 2;
-}
-
-message GetEntityResponse {
- bool exists = 1;
- EntityMetadata entity = 2;
-}
-
-message EntityQuery {
- google.protobuf.StringValue instanceIdStartsWith = 1;
- google.protobuf.Timestamp lastModifiedFrom = 2;
- google.protobuf.Timestamp lastModifiedTo = 3;
- bool includeState = 4;
- bool includeTransient = 5;
- google.protobuf.Int32Value pageSize = 6;
- google.protobuf.StringValue continuationToken = 7;
-}
-
-message QueryEntitiesRequest {
- EntityQuery query = 1;
-}
-
-message QueryEntitiesResponse {
- repeated EntityMetadata entities = 1;
- google.protobuf.StringValue continuationToken = 2;
-}
-
-message EntityMetadata {
- string instanceId = 1;
- google.protobuf.Timestamp lastModifiedTime = 2;
- int32 backlogQueueSize = 3;
- google.protobuf.StringValue lockedBy = 4;
- google.protobuf.StringValue serializedState = 5;
-}
-
-message CleanEntityStorageRequest {
- google.protobuf.StringValue continuationToken = 1;
- bool removeEmptyEntities = 2;
- bool releaseOrphanedLocks = 3;
-}
-
-message CleanEntityStorageResponse {
- google.protobuf.StringValue continuationToken = 1;
- int32 emptyEntitiesRemoved = 2;
- int32 orphanedLocksReleased = 3;
-}
-
-message OrchestratorEntityParameters {
- google.protobuf.Duration entityMessageReorderWindow = 1;
-}
-
-message EntityBatchRequest {
- string instanceId = 1;
- google.protobuf.StringValue entityState = 2;
- repeated OperationRequest operations = 3;
-}
-
-message EntityBatchResult {
- repeated OperationResult results = 1;
- repeated OperationAction actions = 2;
- google.protobuf.StringValue entityState = 3;
- TaskFailureDetails failureDetails = 4;
- string completionToken = 5;
- repeated OperationInfo operationInfos = 6; // used only with DTS
-}
-
-message EntityRequest {
- string instanceId = 1;
- string executionId = 2;
- google.protobuf.StringValue entityState = 3; // null if entity does not exist
- repeated HistoryEvent operationRequests = 4;
-}
-
-message OperationRequest {
- string operation = 1;
- string requestId = 2;
- google.protobuf.StringValue input = 3;
- TraceContext traceContext = 4;
-}
-
-message OperationResult {
- oneof resultType {
- OperationResultSuccess success = 1;
- OperationResultFailure failure = 2;
- }
-}
-
-message OperationInfo {
- string requestId = 1;
- OrchestrationInstance responseDestination = 2; // null for signals
-}
-
-message OperationResultSuccess {
- google.protobuf.StringValue result = 1;
- google.protobuf.Timestamp startTimeUtc = 2;
- google.protobuf.Timestamp endTimeUtc = 3;
-}
-
-message OperationResultFailure {
- TaskFailureDetails failureDetails = 1;
- google.protobuf.Timestamp startTimeUtc = 2;
- google.protobuf.Timestamp endTimeUtc = 3;
-}
-
-message OperationAction {
- int32 id = 1;
- oneof operationActionType {
- SendSignalAction sendSignal = 2;
- StartNewOrchestrationAction startNewOrchestration = 3;
- }
-}
-
-message SendSignalAction {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue input = 3;
- google.protobuf.Timestamp scheduledTime = 4;
- google.protobuf.Timestamp requestTime = 5;
- TraceContext parentTraceContext = 6;
-}
-
-message StartNewOrchestrationAction {
- string instanceId = 1;
- string name = 2;
- google.protobuf.StringValue version = 3;
- google.protobuf.StringValue input = 4;
- google.protobuf.Timestamp scheduledTime = 5;
- google.protobuf.Timestamp requestTime = 6;
- TraceContext parentTraceContext = 7;
-}
-
-message AbandonActivityTaskRequest {
- string completionToken = 1;
-}
-
-message AbandonActivityTaskResponse {
- // Empty.
-}
-
-message AbandonOrchestrationTaskRequest {
- string completionToken = 1;
-}
-
-message AbandonOrchestrationTaskResponse {
- // Empty.
-}
-
-message AbandonEntityTaskRequest {
- string completionToken = 1;
-}
-
-message AbandonEntityTaskResponse {
- // Empty.
-}
-
-message SkipGracefulOrchestrationTerminationsRequest {
- // A maximum of 500 instance IDs can be provided in this list.
- repeated string instanceIds = 1;
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+syntax = "proto3";
+
+option csharp_namespace = "Microsoft.DurableTask.Protobuf";
+option java_package = "com.microsoft.durabletask.implementation.protobuf";
+option go_package = "/internal/protos";
+
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/wrappers.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/struct.proto";
+
+message OrchestrationInstance {
+ string instanceId = 1;
+ google.protobuf.StringValue executionId = 2;
+}
+
+message ActivityRequest {
+ string name = 1;
+ google.protobuf.StringValue version = 2;
+ google.protobuf.StringValue input = 3;
+ OrchestrationInstance orchestrationInstance = 4;
+ int32 taskId = 5;
+ TraceContext parentTraceContext = 6;
+}
+
+message ActivityResponse {
+ string instanceId = 1;
+ int32 taskId = 2;
+ google.protobuf.StringValue result = 3;
+ TaskFailureDetails failureDetails = 4;
+ string completionToken = 5;
+}
+
+message TaskFailureDetails {
+ string errorType = 1;
+ string errorMessage = 2;
+ google.protobuf.StringValue stackTrace = 3;
+ TaskFailureDetails innerFailure = 4;
+ bool isNonRetriable = 5;
+ map properties = 6;
+}
+
+enum OrchestrationStatus {
+ ORCHESTRATION_STATUS_RUNNING = 0;
+ ORCHESTRATION_STATUS_COMPLETED = 1;
+ ORCHESTRATION_STATUS_CONTINUED_AS_NEW = 2;
+ ORCHESTRATION_STATUS_FAILED = 3;
+ ORCHESTRATION_STATUS_CANCELED = 4;
+ ORCHESTRATION_STATUS_TERMINATED = 5;
+ ORCHESTRATION_STATUS_PENDING = 6;
+ ORCHESTRATION_STATUS_SUSPENDED = 7;
+}
+
+message ParentInstanceInfo {
+ int32 taskScheduledId = 1;
+ google.protobuf.StringValue name = 2;
+ google.protobuf.StringValue version = 3;
+ OrchestrationInstance orchestrationInstance = 4;
+}
+
+message TraceContext {
+ string traceParent = 1;
+ string spanID = 2 [deprecated=true];
+ google.protobuf.StringValue traceState = 3;
+}
+
+message ExecutionStartedEvent {
+ string name = 1;
+ google.protobuf.StringValue version = 2;
+ google.protobuf.StringValue input = 3;
+ OrchestrationInstance orchestrationInstance = 4;
+ ParentInstanceInfo parentInstance = 5;
+ google.protobuf.Timestamp scheduledStartTimestamp = 6;
+ TraceContext parentTraceContext = 7;
+ google.protobuf.StringValue orchestrationSpanID = 8;
+ map tags = 9;
+}
+
+message ExecutionCompletedEvent {
+ OrchestrationStatus orchestrationStatus = 1;
+ google.protobuf.StringValue result = 2;
+ TaskFailureDetails failureDetails = 3;
+}
+
+message ExecutionTerminatedEvent {
+ google.protobuf.StringValue input = 1;
+ bool recurse = 2;
+}
+
+message TaskScheduledEvent {
+ string name = 1;
+ google.protobuf.StringValue version = 2;
+ google.protobuf.StringValue input = 3;
+ TraceContext parentTraceContext = 4;
+ map tags = 5;
+}
+
+message TaskCompletedEvent {
+ int32 taskScheduledId = 1;
+ google.protobuf.StringValue result = 2;
+}
+
+message TaskFailedEvent {
+ int32 taskScheduledId = 1;
+ TaskFailureDetails failureDetails = 2;
+}
+
+message SubOrchestrationInstanceCreatedEvent {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue version = 3;
+ google.protobuf.StringValue input = 4;
+ TraceContext parentTraceContext = 5;
+}
+
+message SubOrchestrationInstanceCompletedEvent {
+ int32 taskScheduledId = 1;
+ google.protobuf.StringValue result = 2;
+}
+
+message SubOrchestrationInstanceFailedEvent {
+ int32 taskScheduledId = 1;
+ TaskFailureDetails failureDetails = 2;
+}
+
+message TimerCreatedEvent {
+ google.protobuf.Timestamp fireAt = 1;
+}
+
+message TimerFiredEvent {
+ google.protobuf.Timestamp fireAt = 1;
+ int32 timerId = 2;
+}
+
+message OrchestratorStartedEvent {
+ // No payload data
+}
+
+message OrchestratorCompletedEvent {
+ // No payload data
+}
+
+message EventSentEvent {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue input = 3;
+}
+
+message EventRaisedEvent {
+ string name = 1;
+ google.protobuf.StringValue input = 2;
+}
+
+message GenericEvent {
+ google.protobuf.StringValue data = 1;
+}
+
+message HistoryStateEvent {
+ OrchestrationState orchestrationState = 1;
+}
+
+message ContinueAsNewEvent {
+ google.protobuf.StringValue input = 1;
+}
+
+message ExecutionSuspendedEvent {
+ google.protobuf.StringValue input = 1;
+}
+
+message ExecutionResumedEvent {
+ google.protobuf.StringValue input = 1;
+}
+
+message EntityOperationSignaledEvent {
+ string requestId = 1;
+ string operation = 2;
+ google.protobuf.Timestamp scheduledTime = 3;
+ google.protobuf.StringValue input = 4;
+ google.protobuf.StringValue targetInstanceId = 5; // used only within histories, null in messages
+}
+
+message EntityOperationCalledEvent {
+ string requestId = 1;
+ string operation = 2;
+ google.protobuf.Timestamp scheduledTime = 3;
+ google.protobuf.StringValue input = 4;
+ google.protobuf.StringValue parentInstanceId = 5; // used only within messages, null in histories
+ google.protobuf.StringValue parentExecutionId = 6; // used only within messages, null in histories
+ google.protobuf.StringValue targetInstanceId = 7; // used only within histories, null in messages
+}
+
+message EntityLockRequestedEvent {
+ string criticalSectionId = 1;
+ repeated string lockSet = 2;
+ int32 position = 3;
+ google.protobuf.StringValue parentInstanceId = 4; // used only within messages, null in histories
+}
+
+message EntityOperationCompletedEvent {
+ string requestId = 1;
+ google.protobuf.StringValue output = 2;
+}
+
+message EntityOperationFailedEvent {
+ string requestId = 1;
+ TaskFailureDetails failureDetails = 2;
+}
+
+message EntityUnlockSentEvent {
+ string criticalSectionId = 1;
+ google.protobuf.StringValue parentInstanceId = 2; // used only within messages, null in histories
+ google.protobuf.StringValue targetInstanceId = 3; // used only within histories, null in messages
+}
+
+message EntityLockGrantedEvent {
+ string criticalSectionId = 1;
+}
+
+message HistoryEvent {
+ int32 eventId = 1;
+ google.protobuf.Timestamp timestamp = 2;
+ oneof eventType {
+ ExecutionStartedEvent executionStarted = 3;
+ ExecutionCompletedEvent executionCompleted = 4;
+ ExecutionTerminatedEvent executionTerminated = 5;
+ TaskScheduledEvent taskScheduled = 6;
+ TaskCompletedEvent taskCompleted = 7;
+ TaskFailedEvent taskFailed = 8;
+ SubOrchestrationInstanceCreatedEvent subOrchestrationInstanceCreated = 9;
+ SubOrchestrationInstanceCompletedEvent subOrchestrationInstanceCompleted = 10;
+ SubOrchestrationInstanceFailedEvent subOrchestrationInstanceFailed = 11;
+ TimerCreatedEvent timerCreated = 12;
+ TimerFiredEvent timerFired = 13;
+ OrchestratorStartedEvent orchestratorStarted = 14;
+ OrchestratorCompletedEvent orchestratorCompleted = 15;
+ EventSentEvent eventSent = 16;
+ EventRaisedEvent eventRaised = 17;
+ GenericEvent genericEvent = 18;
+ HistoryStateEvent historyState = 19;
+ ContinueAsNewEvent continueAsNew = 20;
+ ExecutionSuspendedEvent executionSuspended = 21;
+ ExecutionResumedEvent executionResumed = 22;
+ EntityOperationSignaledEvent entityOperationSignaled = 23;
+ EntityOperationCalledEvent entityOperationCalled = 24;
+ EntityOperationCompletedEvent entityOperationCompleted = 25;
+ EntityOperationFailedEvent entityOperationFailed = 26;
+ EntityLockRequestedEvent entityLockRequested = 27;
+ EntityLockGrantedEvent entityLockGranted = 28;
+ EntityUnlockSentEvent entityUnlockSent = 29;
+ }
+}
+
+message ScheduleTaskAction {
+ string name = 1;
+ google.protobuf.StringValue version = 2;
+ google.protobuf.StringValue input = 3;
+ map tags = 4;
+ TraceContext parentTraceContext = 5;
+}
+
+message CreateSubOrchestrationAction {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue version = 3;
+ google.protobuf.StringValue input = 4;
+ TraceContext parentTraceContext = 5;
+}
+
+message CreateTimerAction {
+ google.protobuf.Timestamp fireAt = 1;
+}
+
+message SendEventAction {
+ OrchestrationInstance instance = 1;
+ string name = 2;
+ google.protobuf.StringValue data = 3;
+}
+
+message CompleteOrchestrationAction {
+ OrchestrationStatus orchestrationStatus = 1;
+ google.protobuf.StringValue result = 2;
+ google.protobuf.StringValue details = 3;
+ google.protobuf.StringValue newVersion = 4;
+ repeated HistoryEvent carryoverEvents = 5;
+ TaskFailureDetails failureDetails = 6;
+}
+
+message TerminateOrchestrationAction {
+ string instanceId = 1;
+ google.protobuf.StringValue reason = 2;
+ bool recurse = 3;
+}
+
+message SendEntityMessageAction {
+ oneof EntityMessageType {
+ EntityOperationSignaledEvent entityOperationSignaled = 1;
+ EntityOperationCalledEvent entityOperationCalled = 2;
+ EntityLockRequestedEvent entityLockRequested = 3;
+ EntityUnlockSentEvent entityUnlockSent = 4;
+ }
+}
+
+message OrchestratorAction {
+ int32 id = 1;
+ oneof orchestratorActionType {
+ ScheduleTaskAction scheduleTask = 2;
+ CreateSubOrchestrationAction createSubOrchestration = 3;
+ CreateTimerAction createTimer = 4;
+ SendEventAction sendEvent = 5;
+ CompleteOrchestrationAction completeOrchestration = 6;
+ TerminateOrchestrationAction terminateOrchestration = 7;
+ SendEntityMessageAction sendEntityMessage = 8;
+ }
+}
+
+message OrchestrationTraceContext {
+ google.protobuf.StringValue spanID = 1;
+ google.protobuf.Timestamp spanStartTime = 2;
+}
+
+message OrchestratorRequest {
+ string instanceId = 1;
+ google.protobuf.StringValue executionId = 2;
+ repeated HistoryEvent pastEvents = 3;
+ repeated HistoryEvent newEvents = 4;
+ OrchestratorEntityParameters entityParameters = 5;
+ bool requiresHistoryStreaming = 6;
+ map properties = 7;
+
+ OrchestrationTraceContext orchestrationTraceContext = 8;
+}
+
+message OrchestratorResponse {
+ string instanceId = 1;
+ repeated OrchestratorAction actions = 2;
+ google.protobuf.StringValue customStatus = 3;
+ string completionToken = 4;
+
+ // The number of work item events that were processed by the orchestrator.
+ // This field is optional. If not set, the service should assume that the orchestrator processed all events.
+ google.protobuf.Int32Value numEventsProcessed = 5;
+ OrchestrationTraceContext orchestrationTraceContext = 6;
+
+ // Whether or not a history is required to complete the original OrchestratorRequest and none was provided.
+ bool requiresHistory = 7;
+}
+
+message CreateInstanceRequest {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue version = 3;
+ google.protobuf.StringValue input = 4;
+ google.protobuf.Timestamp scheduledStartTimestamp = 5;
+ OrchestrationIdReusePolicy orchestrationIdReusePolicy = 6;
+ google.protobuf.StringValue executionId = 7;
+ map tags = 8;
+ TraceContext parentTraceContext = 9;
+ google.protobuf.Timestamp requestTime = 10;
+}
+
+message OrchestrationIdReusePolicy {
+ repeated OrchestrationStatus replaceableStatus = 1;
+ reserved 2;
+}
+
+message CreateInstanceResponse {
+ string instanceId = 1;
+}
+
+message GetInstanceRequest {
+ string instanceId = 1;
+ bool getInputsAndOutputs = 2;
+}
+
+message GetInstanceResponse {
+ bool exists = 1;
+ OrchestrationState orchestrationState = 2;
+}
+
+message RewindInstanceRequest {
+ string instanceId = 1;
+ google.protobuf.StringValue reason = 2;
+}
+
+message RewindInstanceResponse {
+ // Empty for now. Using explicit type incase we want to add content later.
+}
+
+message OrchestrationState {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue version = 3;
+ OrchestrationStatus orchestrationStatus = 4;
+ google.protobuf.Timestamp scheduledStartTimestamp = 5;
+ google.protobuf.Timestamp createdTimestamp = 6;
+ google.protobuf.Timestamp lastUpdatedTimestamp = 7;
+ google.protobuf.StringValue input = 8;
+ google.protobuf.StringValue output = 9;
+ google.protobuf.StringValue customStatus = 10;
+ TaskFailureDetails failureDetails = 11;
+ google.protobuf.StringValue executionId = 12;
+ google.protobuf.Timestamp completedTimestamp = 13;
+ google.protobuf.StringValue parentInstanceId = 14;
+ map tags = 15;
+}
+
+message RaiseEventRequest {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue input = 3;
+}
+
+message RaiseEventResponse {
+ // No payload
+}
+
+message TerminateRequest {
+ string instanceId = 1;
+ google.protobuf.StringValue output = 2;
+ bool recursive = 3;
+}
+
+message TerminateResponse {
+ // No payload
+}
+
+message SuspendRequest {
+ string instanceId = 1;
google.protobuf.StringValue reason = 2;
-}
-
-message SkipGracefulOrchestrationTerminationsResponse {
- // Those instances which could not be terminated because they had locked entities at the time of this termination call,
- // are already in a terminal state (completed, failed, terminated, etc.), are not orchestrations, or do not exist (i.e. have been purged)
+}
+
+message SuspendResponse {
+ // No payload
+}
+
+message ResumeRequest {
+ string instanceId = 1;
+ google.protobuf.StringValue reason = 2;
+}
+
+message ResumeResponse {
+ // No payload
+}
+
+message QueryInstancesRequest {
+ InstanceQuery query = 1;
+}
+
+message InstanceQuery{
+ repeated OrchestrationStatus runtimeStatus = 1;
+ google.protobuf.Timestamp createdTimeFrom = 2;
+ google.protobuf.Timestamp createdTimeTo = 3;
+ repeated google.protobuf.StringValue taskHubNames = 4;
+ int32 maxInstanceCount = 5;
+ google.protobuf.StringValue continuationToken = 6;
+ google.protobuf.StringValue instanceIdPrefix = 7;
+ bool fetchInputsAndOutputs = 8;
+}
+
+message QueryInstancesResponse {
+ repeated OrchestrationState orchestrationState = 1;
+ google.protobuf.StringValue continuationToken = 2;
+}
+
+message PurgeInstancesRequest {
+ oneof request {
+ string instanceId = 1;
+ PurgeInstanceFilter purgeInstanceFilter = 2;
+ InstanceBatch instanceBatch = 4;
+ }
+ bool recursive = 3;
+}
+
+message PurgeInstanceFilter {
+ google.protobuf.Timestamp createdTimeFrom = 1;
+ google.protobuf.Timestamp createdTimeTo = 2;
+ repeated OrchestrationStatus runtimeStatus = 3;
+}
+
+message PurgeInstancesResponse {
+ int32 deletedInstanceCount = 1;
+ google.protobuf.BoolValue isComplete = 2;
+}
+
+message RestartInstanceRequest {
+ string instanceId = 1;
+ bool restartWithNewInstanceId = 2;
+}
+
+message RestartInstanceResponse {
+ string instanceId = 1;
+}
+
+message CreateTaskHubRequest {
+ bool recreateIfExists = 1;
+}
+
+message CreateTaskHubResponse {
+ //no playload
+}
+
+message DeleteTaskHubRequest {
+ //no playload
+}
+
+message DeleteTaskHubResponse {
+ //no playload
+}
+
+message SignalEntityRequest {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue input = 3;
+ string requestId = 4;
+ google.protobuf.Timestamp scheduledTime = 5;
+ TraceContext parentTraceContext = 6;
+ google.protobuf.Timestamp requestTime = 7;
+}
+
+message SignalEntityResponse {
+ // no payload
+}
+
+message GetEntityRequest {
+ string instanceId = 1;
+ bool includeState = 2;
+}
+
+message GetEntityResponse {
+ bool exists = 1;
+ EntityMetadata entity = 2;
+}
+
+message EntityQuery {
+ google.protobuf.StringValue instanceIdStartsWith = 1;
+ google.protobuf.Timestamp lastModifiedFrom = 2;
+ google.protobuf.Timestamp lastModifiedTo = 3;
+ bool includeState = 4;
+ bool includeTransient = 5;
+ google.protobuf.Int32Value pageSize = 6;
+ google.protobuf.StringValue continuationToken = 7;
+}
+
+message QueryEntitiesRequest {
+ EntityQuery query = 1;
+}
+
+message QueryEntitiesResponse {
+ repeated EntityMetadata entities = 1;
+ google.protobuf.StringValue continuationToken = 2;
+}
+
+message EntityMetadata {
+ string instanceId = 1;
+ google.protobuf.Timestamp lastModifiedTime = 2;
+ int32 backlogQueueSize = 3;
+ google.protobuf.StringValue lockedBy = 4;
+ google.protobuf.StringValue serializedState = 5;
+}
+
+message CleanEntityStorageRequest {
+ google.protobuf.StringValue continuationToken = 1;
+ bool removeEmptyEntities = 2;
+ bool releaseOrphanedLocks = 3;
+}
+
+message CleanEntityStorageResponse {
+ google.protobuf.StringValue continuationToken = 1;
+ int32 emptyEntitiesRemoved = 2;
+ int32 orphanedLocksReleased = 3;
+}
+
+message OrchestratorEntityParameters {
+ google.protobuf.Duration entityMessageReorderWindow = 1;
+}
+
+message EntityBatchRequest {
+ string instanceId = 1;
+ google.protobuf.StringValue entityState = 2;
+ repeated OperationRequest operations = 3;
+}
+
+message EntityBatchResult {
+ repeated OperationResult results = 1;
+ repeated OperationAction actions = 2;
+ google.protobuf.StringValue entityState = 3;
+ TaskFailureDetails failureDetails = 4;
+ string completionToken = 5;
+ repeated OperationInfo operationInfos = 6; // used only with DTS
+}
+
+message EntityRequest {
+ string instanceId = 1;
+ string executionId = 2;
+ google.protobuf.StringValue entityState = 3; // null if entity does not exist
+ repeated HistoryEvent operationRequests = 4;
+}
+
+message OperationRequest {
+ string operation = 1;
+ string requestId = 2;
+ google.protobuf.StringValue input = 3;
+ TraceContext traceContext = 4;
+}
+
+message OperationResult {
+ oneof resultType {
+ OperationResultSuccess success = 1;
+ OperationResultFailure failure = 2;
+ }
+}
+
+message OperationInfo {
+ string requestId = 1;
+ OrchestrationInstance responseDestination = 2; // null for signals
+}
+
+message OperationResultSuccess {
+ google.protobuf.StringValue result = 1;
+ google.protobuf.Timestamp startTimeUtc = 2;
+ google.protobuf.Timestamp endTimeUtc = 3;
+}
+
+message OperationResultFailure {
+ TaskFailureDetails failureDetails = 1;
+ google.protobuf.Timestamp startTimeUtc = 2;
+ google.protobuf.Timestamp endTimeUtc = 3;
+}
+
+message OperationAction {
+ int32 id = 1;
+ oneof operationActionType {
+ SendSignalAction sendSignal = 2;
+ StartNewOrchestrationAction startNewOrchestration = 3;
+ }
+}
+
+message SendSignalAction {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue input = 3;
+ google.protobuf.Timestamp scheduledTime = 4;
+ google.protobuf.Timestamp requestTime = 5;
+ TraceContext parentTraceContext = 6;
+}
+
+message StartNewOrchestrationAction {
+ string instanceId = 1;
+ string name = 2;
+ google.protobuf.StringValue version = 3;
+ google.protobuf.StringValue input = 4;
+ google.protobuf.Timestamp scheduledTime = 5;
+ google.protobuf.Timestamp requestTime = 6;
+ TraceContext parentTraceContext = 7;
+}
+
+message AbandonActivityTaskRequest {
+ string completionToken = 1;
+}
+
+message AbandonActivityTaskResponse {
+ // Empty.
+}
+
+message AbandonOrchestrationTaskRequest {
+ string completionToken = 1;
+}
+
+message AbandonOrchestrationTaskResponse {
+ // Empty.
+}
+
+message AbandonEntityTaskRequest {
+ string completionToken = 1;
+}
+
+message AbandonEntityTaskResponse {
+ // Empty.
+}
+
+message SkipGracefulOrchestrationTerminationsRequest {
+ InstanceBatch instanceBatch = 1;
+ google.protobuf.StringValue reason = 2;
+}
+
+message SkipGracefulOrchestrationTerminationsResponse {
+ // Those instances which could not be terminated because they had locked entities at the time of this termination call,
+ // are already in a terminal state (completed, failed, terminated, etc.), are not orchestrations, or do not exist (i.e. have been purged)
repeated string unterminatedInstanceIds = 1;
-}
-
-service TaskHubSidecarService {
- // Sends a hello request to the sidecar service.
- rpc Hello(google.protobuf.Empty) returns (google.protobuf.Empty);
-
- // Starts a new orchestration instance.
- rpc StartInstance(CreateInstanceRequest) returns (CreateInstanceResponse);
-
- // Gets the status of an existing orchestration instance.
- rpc GetInstance(GetInstanceRequest) returns (GetInstanceResponse);
-
- // Rewinds an orchestration instance to last known good state and replays from there.
- rpc RewindInstance(RewindInstanceRequest) returns (RewindInstanceResponse);
-
- // Restarts an orchestration instance.
- rpc RestartInstance(RestartInstanceRequest) returns (RestartInstanceResponse);
-
- // Waits for an orchestration instance to reach a running or completion state.
- rpc WaitForInstanceStart(GetInstanceRequest) returns (GetInstanceResponse);
-
- // Waits for an orchestration instance to reach a completion state (completed, failed, terminated, etc.).
- rpc WaitForInstanceCompletion(GetInstanceRequest) returns (GetInstanceResponse);
-
- // Raises an event to a running orchestration instance.
- rpc RaiseEvent(RaiseEventRequest) returns (RaiseEventResponse);
-
- // Terminates a running orchestration instance.
- rpc TerminateInstance(TerminateRequest) returns (TerminateResponse);
-
- // Suspends a running orchestration instance.
- rpc SuspendInstance(SuspendRequest) returns (SuspendResponse);
-
- // Resumes a suspended orchestration instance.
- rpc ResumeInstance(ResumeRequest) returns (ResumeResponse);
-
- // rpc DeleteInstance(DeleteInstanceRequest) returns (DeleteInstanceResponse);
-
- rpc QueryInstances(QueryInstancesRequest) returns (QueryInstancesResponse);
- rpc PurgeInstances(PurgeInstancesRequest) returns (PurgeInstancesResponse);
-
- rpc GetWorkItems(GetWorkItemsRequest) returns (stream WorkItem);
- rpc CompleteActivityTask(ActivityResponse) returns (CompleteTaskResponse);
- rpc CompleteOrchestratorTask(OrchestratorResponse) returns (CompleteTaskResponse);
- rpc CompleteEntityTask(EntityBatchResult) returns (CompleteTaskResponse);
-
- // Gets the history of an orchestration instance as a stream of events.
- rpc StreamInstanceHistory(StreamInstanceHistoryRequest) returns (stream HistoryChunk);
-
- // Deletes and Creates the necessary resources for the orchestration service and the instance store
- rpc CreateTaskHub(CreateTaskHubRequest) returns (CreateTaskHubResponse);
-
- // Deletes the resources for the orchestration service and optionally the instance store
- rpc DeleteTaskHub(DeleteTaskHubRequest) returns (DeleteTaskHubResponse);
-
- // sends a signal to an entity
- rpc SignalEntity(SignalEntityRequest) returns (SignalEntityResponse);
-
- // get information about a specific entity
- rpc GetEntity(GetEntityRequest) returns (GetEntityResponse);
-
- // query entities
- rpc QueryEntities(QueryEntitiesRequest) returns (QueryEntitiesResponse);
-
- // clean entity storage
- rpc CleanEntityStorage(CleanEntityStorageRequest) returns (CleanEntityStorageResponse);
-
- // Abandons a single work item
- rpc AbandonTaskActivityWorkItem(AbandonActivityTaskRequest) returns (AbandonActivityTaskResponse);
-
- // Abandon an orchestration work item
- rpc AbandonTaskOrchestratorWorkItem(AbandonOrchestrationTaskRequest) returns (AbandonOrchestrationTaskResponse);
-
- // Abandon an entity work item
- rpc AbandonTaskEntityWorkItem(AbandonEntityTaskRequest) returns (AbandonEntityTaskResponse);
-
- // "Skip" graceful termination of orchestrations by immediately changing their status in storage to "terminated".
- // Note that a maximum of 500 orchestrations can be terminated at a time using this method.
- rpc SkipGracefulOrchestrationTerminations(SkipGracefulOrchestrationTerminationsRequest) returns (SkipGracefulOrchestrationTerminationsResponse);
-}
-
-message GetWorkItemsRequest {
- int32 maxConcurrentOrchestrationWorkItems = 1;
- int32 maxConcurrentActivityWorkItems = 2;
- int32 maxConcurrentEntityWorkItems = 3;
-
- repeated WorkerCapability capabilities = 10;
-}
-
-enum WorkerCapability {
- WORKER_CAPABILITY_UNSPECIFIED = 0;
-
- // Indicates that the worker is capable of streaming instance history as a more optimized
- // alternative to receiving the full history embedded in the orchestrator work-item.
- // When set, the service may return work items without any history events as an optimization.
- // It is strongly recommended that all SDKs support this capability.
- WORKER_CAPABILITY_HISTORY_STREAMING = 1;
-}
-
-message WorkItem {
- oneof request {
- OrchestratorRequest orchestratorRequest = 1;
- ActivityRequest activityRequest = 2;
- EntityBatchRequest entityRequest = 3; // (older) used by orchestration services implementations
- HealthPing healthPing = 4;
- EntityRequest entityRequestV2 = 5; // (newer) used by backend service implementations
- }
- string completionToken = 10;
-}
-
-message CompleteTaskResponse {
- // No payload
-}
-
-message HealthPing {
- // No payload
-}
-
-message StreamInstanceHistoryRequest {
- string instanceId = 1;
- google.protobuf.StringValue executionId = 2;
-
- // When set to true, the service may return a more optimized response suitable for workers.
- bool forWorkItemProcessing = 3;
-}
-
-message HistoryChunk {
- repeated HistoryEvent events = 1;
-}
\ No newline at end of file
+
+}
+
+service TaskHubSidecarService {
+ // Sends a hello request to the sidecar service.
+ rpc Hello(google.protobuf.Empty) returns (google.protobuf.Empty);
+
+ // Starts a new orchestration instance.
+ rpc StartInstance(CreateInstanceRequest) returns (CreateInstanceResponse);
+
+ // Gets the status of an existing orchestration instance.
+ rpc GetInstance(GetInstanceRequest) returns (GetInstanceResponse);
+
+ // Rewinds an orchestration instance to last known good state and replays from there.
+ rpc RewindInstance(RewindInstanceRequest) returns (RewindInstanceResponse);
+
+ // Restarts an orchestration instance.
+ rpc RestartInstance(RestartInstanceRequest) returns (RestartInstanceResponse);
+
+ // Waits for an orchestration instance to reach a running or completion state.
+ rpc WaitForInstanceStart(GetInstanceRequest) returns (GetInstanceResponse);
+
+ // Waits for an orchestration instance to reach a completion state (completed, failed, terminated, etc.).
+ rpc WaitForInstanceCompletion(GetInstanceRequest) returns (GetInstanceResponse);
+
+ // Raises an event to a running orchestration instance.
+ rpc RaiseEvent(RaiseEventRequest) returns (RaiseEventResponse);
+
+ // Terminates a running orchestration instance.
+ rpc TerminateInstance(TerminateRequest) returns (TerminateResponse);
+
+ // Suspends a running orchestration instance.
+ rpc SuspendInstance(SuspendRequest) returns (SuspendResponse);
+
+ // Resumes a suspended orchestration instance.
+ rpc ResumeInstance(ResumeRequest) returns (ResumeResponse);
+
+ // rpc DeleteInstance(DeleteInstanceRequest) returns (DeleteInstanceResponse);
+
+ rpc QueryInstances(QueryInstancesRequest) returns (QueryInstancesResponse);
+ rpc PurgeInstances(PurgeInstancesRequest) returns (PurgeInstancesResponse);
+
+ rpc GetWorkItems(GetWorkItemsRequest) returns (stream WorkItem);
+ rpc CompleteActivityTask(ActivityResponse) returns (CompleteTaskResponse);
+ rpc CompleteOrchestratorTask(OrchestratorResponse) returns (CompleteTaskResponse);
+ rpc CompleteEntityTask(EntityBatchResult) returns (CompleteTaskResponse);
+
+ // Gets the history of an orchestration instance as a stream of events.
+ rpc StreamInstanceHistory(StreamInstanceHistoryRequest) returns (stream HistoryChunk);
+
+ // Deletes and Creates the necessary resources for the orchestration service and the instance store
+ rpc CreateTaskHub(CreateTaskHubRequest) returns (CreateTaskHubResponse);
+
+ // Deletes the resources for the orchestration service and optionally the instance store
+ rpc DeleteTaskHub(DeleteTaskHubRequest) returns (DeleteTaskHubResponse);
+
+ // sends a signal to an entity
+ rpc SignalEntity(SignalEntityRequest) returns (SignalEntityResponse);
+
+ // get information about a specific entity
+ rpc GetEntity(GetEntityRequest) returns (GetEntityResponse);
+
+ // query entities
+ rpc QueryEntities(QueryEntitiesRequest) returns (QueryEntitiesResponse);
+
+ // clean entity storage
+ rpc CleanEntityStorage(CleanEntityStorageRequest) returns (CleanEntityStorageResponse);
+
+ // Abandons a single work item
+ rpc AbandonTaskActivityWorkItem(AbandonActivityTaskRequest) returns (AbandonActivityTaskResponse);
+
+ // Abandon an orchestration work item
+ rpc AbandonTaskOrchestratorWorkItem(AbandonOrchestrationTaskRequest) returns (AbandonOrchestrationTaskResponse);
+
+ // Abandon an entity work item
+ rpc AbandonTaskEntityWorkItem(AbandonEntityTaskRequest) returns (AbandonEntityTaskResponse);
+
+ // "Skip" graceful termination of orchestrations by immediately changing their status in storage to "terminated".
+ // Note that a maximum of 500 orchestrations can be terminated at a time using this method.
+ rpc SkipGracefulOrchestrationTerminations(SkipGracefulOrchestrationTerminationsRequest) returns (SkipGracefulOrchestrationTerminationsResponse);
+}
+
+message GetWorkItemsRequest {
+ int32 maxConcurrentOrchestrationWorkItems = 1;
+ int32 maxConcurrentActivityWorkItems = 2;
+ int32 maxConcurrentEntityWorkItems = 3;
+
+ repeated WorkerCapability capabilities = 10;
+}
+
+enum WorkerCapability {
+ WORKER_CAPABILITY_UNSPECIFIED = 0;
+
+ // Indicates that the worker is capable of streaming instance history as a more optimized
+ // alternative to receiving the full history embedded in the orchestrator work-item.
+ // When set, the service may return work items without any history events as an optimization.
+ // It is strongly recommended that all SDKs support this capability.
+ WORKER_CAPABILITY_HISTORY_STREAMING = 1;
+}
+
+message WorkItem {
+ oneof request {
+ OrchestratorRequest orchestratorRequest = 1;
+ ActivityRequest activityRequest = 2;
+ EntityBatchRequest entityRequest = 3; // (older) used by orchestration services implementations
+ HealthPing healthPing = 4;
+ EntityRequest entityRequestV2 = 5; // (newer) used by backend service implementations
+ }
+ string completionToken = 10;
+}
+
+message CompleteTaskResponse {
+ // No payload
+}
+
+message HealthPing {
+ // No payload
+}
+
+message StreamInstanceHistoryRequest {
+ string instanceId = 1;
+ google.protobuf.StringValue executionId = 2;
+
+ // When set to true, the service may return a more optimized response suitable for workers.
+ bool forWorkItemProcessing = 3;
+}
+
+message HistoryChunk {
+ repeated HistoryEvent events = 1;
+}
+
+message InstanceBatch {
+ // A maximum of 500 instance IDs can be provided in this list.
+ repeated string instanceIds = 1;
+}
diff --git a/src/WebJobs.Extensions.DurableTask/Grpc/Protos/versions.txt b/src/WebJobs.Extensions.DurableTask/Grpc/Protos/versions.txt
index b4a20b9e3..178b7c3fe 100644
--- a/src/WebJobs.Extensions.DurableTask/Grpc/Protos/versions.txt
+++ b/src/WebJobs.Extensions.DurableTask/Grpc/Protos/versions.txt
@@ -1,2 +1,2 @@
-# The following files were downloaded from branch main at 2025-09-17 01:59:32 UTC
-https://raw.githubusercontent.com/microsoft/durabletask-protobuf/f5745e0d83f608d77871c1894d9260ceaae08967/protos/orchestrator_service.proto
+# The following files were downloaded from branch nytian/failure-details at 2025-10-06 02:42:27 UTC
+https://raw.githubusercontent.com/microsoft/durabletask-protobuf/362f886f1ef7c4dd90cbdfdb2f661f48eeeec4fa/protos/orchestrator_service.proto
diff --git a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs
index 0aeaa9440..090bac187 100644
--- a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs
+++ b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Text.Json.Nodes;
using System.Threading.Tasks;
using DurableTask.Core;
using DurableTask.Core.Entities;
@@ -12,6 +13,7 @@
using DurableTask.Core.Exceptions;
using DurableTask.Core.History;
using DurableTask.Core.Middleware;
+using Google.Protobuf.WellKnownTypes;
using Microsoft.Azure.WebJobs.Host.Executors;
using Newtonsoft.Json;
using P = Microsoft.DurableTask.Protobuf;
@@ -205,9 +207,9 @@ await this.LifeCycleNotificationHelper.OrchestratorStartingAsync(
OrchestratorExecutionResult orchestratorResult;
if (functionResult.Succeeded)
{
- if (workerRequiresHistory)
- {
- throw new SessionAbortedException("The worker has since ended the extended session and needs an orchestration history to execute the orchestration request.");
+ if (workerRequiresHistory)
+ {
+ throw new SessionAbortedException("The worker has since ended the extended session and needs an orchestration history to execute the orchestration request.");
}
orchestratorResult = context.GetResult();
@@ -637,12 +639,15 @@ private static FailureDetails GetFailureDetails(Exception e, out bool fromSerial
return details;
}
+ // Try to extract properties from the serialized exception JSON
+ IDictionary? properties = TryExtractPropertiesFromExceptionJson(exception);
+
if (TrySplitExceptionTypeFromMessage(exception, out string? exceptionType, out string? exceptionMessage))
{
- return new FailureDetails(exceptionType, exceptionMessage, stackTrace, innerFailure: null, isNonRetriable: false);
+ return new FailureDetails(exceptionType, exceptionMessage, stackTrace, innerFailure: null, isNonRetriable: false, properties: properties);
}
- return new FailureDetails("(unknown)", exception, stackTrace, innerFailure: null, isNonRetriable: false);
+ return new FailureDetails("(unknown)", exception, stackTrace, innerFailure: null, isNonRetriable: false, properties: properties);
}
else
{
@@ -662,12 +667,44 @@ private static FailureDetails GetFailureDetails(Exception e, out bool fromSerial
return null;
}
+ IDictionary? properties = null;
+ if (taskFailureDetails.Properties != null && taskFailureDetails.Properties.Count > 0)
+ {
+ properties = new Dictionary();
+ foreach (var kvp in taskFailureDetails.Properties)
+ {
+ properties[kvp.Key] = ConvertValueToObject(kvp.Value);
+ }
+ }
+
return new FailureDetails(
taskFailureDetails.ErrorType ?? string.Empty,
taskFailureDetails.ErrorMessage ?? string.Empty,
taskFailureDetails.StackTrace,
GetFailureDetails(taskFailureDetails.InnerFailure),
- taskFailureDetails.IsNonRetriable);
+ taskFailureDetails.IsNonRetriable,
+ properties);
+ }
+
+ private static object ConvertValueToObject(Value value)
+ {
+ switch (value.KindCase)
+ {
+ case Value.KindOneofCase.StringValue:
+ return value.StringValue;
+ case Value.KindOneofCase.NumberValue:
+ return value.NumberValue;
+ case Value.KindOneofCase.BoolValue:
+ return value.BoolValue;
+ case Value.KindOneofCase.StructValue:
+ return value.StructValue.Fields.ToDictionary(f => f.Key, f => ConvertValueToObject(f.Value));
+ case Value.KindOneofCase.ListValue:
+ return value.ListValue.Values.Select(ConvertValueToObject).ToList();
+ case Value.KindOneofCase.NullValue:
+ return null!;
+ default:
+ return value; // fallback
+ }
}
private static bool TryGetRpcExceptionFields(
@@ -739,6 +776,69 @@ private static bool TryExtractSerializedFailureDetailsFromException(string excep
details = null;
return false;
}
+
+ public static IDictionary TryExtractPropertiesFromExceptionJson(string json)
+ {
+ var result = new Dictionary();
+ var root = JsonNode.Parse(json)?["Properties"]?.AsObject();
+ if (root == null)
+ {
+ return result;
+ }
+
+ foreach (var kvp in root)
+ {
+ var valueNode = kvp.Value?.AsObject();
+ if (valueNode == null)
+ {
+ continue;
+ }
+
+ result[kvp.Key] = ExtractValue(valueNode);
+ }
+
+ return result;
+ }
+
+ private static object? ExtractValue(JsonObject valueNode)
+ {
+ // Look at KindCase to determine which field is active
+ if (valueNode.TryGetPropertyValue("HasStringValue", out var hasStr)
+ && hasStr?.GetValue() == true)
+ {
+ return valueNode["StringValue"]?.GetValue();
+ }
+
+ if (valueNode.TryGetPropertyValue("HasNumberValue", out var hasNum)
+ && hasNum?.GetValue() == true)
+ {
+ return valueNode["NumberValue"]?.GetValue();
+ }
+
+ if (valueNode.TryGetPropertyValue("HasBoolValue", out var hasBool)
+ && hasBool?.GetValue() == true)
+ {
+ return valueNode["BoolValue"]?.GetValue();
+ }
+
+ if (valueNode.TryGetPropertyValue("HasNullValue", out var hasNull)
+ && hasNull?.GetValue() == true)
+ {
+ return null;
+ }
+
+ if (valueNode["StructValue"] is JsonObject structObj)
+ {
+ return structObj;
+ }
+
+ if (valueNode["ListValue"] is JsonArray listArr)
+ {
+ return listArr.Select(x => x?.ToJsonString()).ToList();
+ }
+
+ return null;
+ }
private static bool TrySplitExceptionTypeFromMessage(
string exception,
diff --git a/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj b/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj
index 3499faa64..278fea87e 100644
--- a/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj
+++ b/src/WebJobs.Extensions.DurableTask/WebJobs.Extensions.DurableTask.csproj
@@ -5,7 +5,7 @@
Microsoft.Azure.WebJobs.Extensions.DurableTask
Microsoft.Azure.WebJobs.Extensions.DurableTask
3
- 5
+ 6
0
$(MajorVersion).$(MinorVersion).$(PatchVersion)
$(MajorVersion).$(MinorVersion).$(PatchVersion)
diff --git a/src/Worker.Extensions.DurableTask/AssemblyInfo.cs b/src/Worker.Extensions.DurableTask/AssemblyInfo.cs
index 061ba9228..6463fa77e 100644
--- a/src/Worker.Extensions.DurableTask/AssemblyInfo.cs
+++ b/src/Worker.Extensions.DurableTask/AssemblyInfo.cs
@@ -5,5 +5,5 @@
using Microsoft.Azure.Functions.Worker.Extensions.Abstractions;
// TODO: Find a way to generate this dynamically at build-time
-[assembly: ExtensionInformation("Microsoft.Azure.WebJobs.Extensions.DurableTask", "3.5.0")]
+[assembly: ExtensionInformation("Microsoft.Azure.WebJobs.Extensions.DurableTask", "3.6.0")]
[assembly: InternalsVisibleTo("Worker.Extensions.DurableTask.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cd1dabd5a893b40e75dc901fe7293db4a3caf9cd4d3e3ed6178d49cd476969abe74a9e0b7f4a0bb15edca48758155d35a4f05e6e852fff1b319d103b39ba04acbadd278c2753627c95e1f6f6582425374b92f51cca3deb0d2aab9de3ecda7753900a31f70a236f163006beefffe282888f85e3c76d1205ec7dfef7fa472a17b1")]
diff --git a/src/Worker.Extensions.DurableTask/DefaultExceptionPropertiesProvider.cs b/src/Worker.Extensions.DurableTask/DefaultExceptionPropertiesProvider.cs
new file mode 100644
index 000000000..b1db243b5
--- /dev/null
+++ b/src/Worker.Extensions.DurableTask/DefaultExceptionPropertiesProvider.cs
@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using Microsoft.DurableTask.Worker;
+
+namespace Microsoft.Azure.Functions.Worker.Extensions.DurableTask;
+
+///
+/// Default implementation of IExceptionPropertiesProvider that returns no custom properties.
+///
+internal class DefaultExceptionPropertiesProvider : IExceptionPropertiesProvider
+{
+ ///
+ public IReadOnlyDictionary? GetExceptionProperties(Exception exception)
+ {
+ // Default implementation returns null, indicating no custom properties should be added
+ return null;
+ }
+
+ IDictionary? IExceptionPropertiesProvider.GetExceptionProperties(Exception exception)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs b/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs
index 1ef56ff7b..efc5fa6cf 100644
--- a/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs
+++ b/src/Worker.Extensions.DurableTask/DurableTaskFunctionsMiddleware.cs
@@ -16,8 +16,8 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.DurableTask;
///
internal class DurableTaskFunctionsMiddleware(ExtendedSessionsCache extendedSessionsCache) : IFunctionsWorkerMiddleware
{
- private readonly ExtendedSessionsCache extendedSessionsCache = extendedSessionsCache;
-
+ private readonly ExtendedSessionsCache extendedSessionsCache = extendedSessionsCache;
+
///
public Task Invoke(FunctionContext functionContext, FunctionExecutionDelegate next)
{
@@ -129,7 +129,9 @@ private static async Task RunActivityAsync(FunctionContext functionContext, Bind
}
catch (Exception ex)
{
- throw new DurableSerializationException(ex);
+ // Get the exception properties provider from the service provider if available
+ IExceptionPropertiesProvider? exceptionPropertiesProvider = functionContext.InstanceServices.GetService(typeof(IExceptionPropertiesProvider)) as IExceptionPropertiesProvider;
+ throw new DurableSerializationException(ex, exceptionPropertiesProvider);
}
}
}
diff --git a/src/Worker.Extensions.DurableTask/Exceptions/DurableSerializationException.cs b/src/Worker.Extensions.DurableTask/Exceptions/DurableSerializationException.cs
index d0c664946..b09665b9a 100644
--- a/src/Worker.Extensions.DurableTask/Exceptions/DurableSerializationException.cs
+++ b/src/Worker.Extensions.DurableTask/Exceptions/DurableSerializationException.cs
@@ -1,5 +1,6 @@
using System;
using Microsoft.DurableTask.Protobuf;
+using Microsoft.DurableTask.Worker;
using Newtonsoft.Json;
namespace Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Exceptions;
@@ -11,7 +12,13 @@ internal class DurableSerializationException : Exception
// We set the base class properties of this exception to the same as the parent,
// so that methods in the worker after this can still (typically) access the same information vs w/o
// this exception type.
- internal DurableSerializationException(Exception fromException) : base(CreateExceptionMessage(fromException), fromException.InnerException)
+ internal DurableSerializationException(Exception fromException) :
+ this(fromException, null)
+ {
+ }
+
+ internal DurableSerializationException(Exception fromException, IExceptionPropertiesProvider? exceptionPropertiesProvider)
+ : base(CreateExceptionMessage(fromException, exceptionPropertiesProvider), fromException.InnerException)
{
this.fromException = fromException;
}
@@ -21,10 +28,9 @@ public override string ToString()
return this.Message;
}
- // Serilize FailureDetails to JSON
- private static string CreateExceptionMessage(Exception ex)
+ private static string CreateExceptionMessage(Exception ex, IExceptionPropertiesProvider? exceptionPropertiesProvider)
{
- TaskFailureDetails? failureDetails = TaskFailureDetailsConverter.TaskFailureFromException(ex);
+ TaskFailureDetails? failureDetails = TaskFailureDetailsConverter.TaskFailureFromException(ex, exceptionPropertiesProvider);
return JsonConvert.SerializeObject(failureDetails);
}
diff --git a/src/Worker.Extensions.DurableTask/TaskFailureDetailsConverter.cs b/src/Worker.Extensions.DurableTask/TaskFailureDetailsConverter.cs
index 4bfbf7b02..1c1f2118d 100644
--- a/src/Worker.Extensions.DurableTask/TaskFailureDetailsConverter.cs
+++ b/src/Worker.Extensions.DurableTask/TaskFailureDetailsConverter.cs
@@ -3,25 +3,72 @@
using System;
using System.Collections.Generic;
-using System.Text;
+using System.Linq;
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.DurableTask.Worker;
using P = Microsoft.DurableTask.Protobuf;
namespace Microsoft.Azure.Functions.Worker.Extensions.DurableTask;
internal class TaskFailureDetailsConverter
{
internal static P.TaskFailureDetails? TaskFailureFromException(Exception? fromException)
+ {
+ return TaskFailureFromException(fromException, null);
+ }
+
+ internal static P.TaskFailureDetails? TaskFailureFromException(Exception? fromException, IExceptionPropertiesProvider? exceptionPropertiesProvider)
{
if (fromException is null)
{
return null;
}
- return new P.TaskFailureDetails()
+
+ var failureDetails = new P.TaskFailureDetails()
{
ErrorType = fromException.GetType().FullName,
ErrorMessage = fromException.Message,
StackTrace = fromException.StackTrace,
- InnerFailure = TaskFailureFromException(fromException.InnerException),
+ InnerFailure = TaskFailureFromException(fromException.InnerException, exceptionPropertiesProvider),
IsNonRetriable = false
};
+
+ // Add custom properties if provider is available
+ if (exceptionPropertiesProvider != null)
+ {
+ var customProperties = exceptionPropertiesProvider.GetExceptionProperties(fromException);
+ if (customProperties != null && customProperties.Count > 0)
+ {
+ foreach (var property in customProperties)
+ {
+ failureDetails.Properties[property.Key] = ConvertObjectToValue(property.Value);
+ }
+ }
+ }
+
+ return failureDetails;
+ }
+
+ private static Value ConvertObjectToValue(object? value)
+ {
+ return value switch
+ {
+ null => Value.ForNull(),
+ string str => Value.ForString(str),
+ bool b => Value.ForBool(b),
+ int i => Value.ForNumber(i),
+ long l => Value.ForNumber(l),
+ float f => Value.ForNumber(f),
+ double d => Value.ForNumber(d),
+ decimal dec => Value.ForNumber((double)dec),
+ DateTime dt => Value.ForString(dt.ToString("O")),
+ DateTimeOffset dto => Value.ForString(dto.ToString("O")),
+ Guid guid => Value.ForString(guid.ToString()),
+ IDictionary dict => Value.ForStruct(new Struct
+ {
+ Fields = { dict.ToDictionary(kvp => kvp.Key, kvp => ConvertObjectToValue(kvp.Value)) },
+ }),
+ IEnumerable