From 47d0071d4ddfc8258b163d00cac778e09c6b17cc Mon Sep 17 00:00:00 2001 From: joshvanl Date: Wed, 9 Sep 2026 13:03:03 -0300 Subject: [PATCH 1/2] Workflow: cross-app client operations Adds an optional app_id argument to every client-level workflow operation on DaprWorkflowClient and its async counterpart: schedule_new_workflow, get_workflow_state, wait_for_workflow_start, wait_for_workflow_completion, raise_workflow_event, terminate_workflow, pause_workflow, resume_workflow and purge_workflow. When set, the operation targets a workflow instance owned by another app in the same namespace, and the target app's WorkflowAccessPolicy decides whether it is permitted. When unset or equal to the local app, the behaviour is unchanged. The vendored durabletask client carries the value as a TaskRouter with targetAppID on each request, built by the new new_task_router helper. An older runtime ignores the field and applies the operation locally. Signed-off-by: joshvanl --- dapr/ext/workflow/_durabletask/aio/client.py | 95 +++++++-- dapr/ext/workflow/_durabletask/client.py | 104 ++++++++-- .../internal/PROTO_SOURCE_COMMIT_HASH | 2 +- .../internal/backend_service_pb2.py | 24 +-- .../internal/backend_service_pb2.pyi | 9 +- .../workflow/_durabletask/internal/helpers.py | 6 +- .../internal/history_events_pb2.py | 84 ++++---- .../internal/history_events_pb2.pyi | 19 +- .../internal/orchestration_pb2.py | 28 +-- .../internal/orchestration_pb2.pyi | 48 ++++- .../internal/orchestrator_actions_pb2.py | 40 ++-- .../internal/orchestrator_actions_pb2.pyi | 49 ++--- .../internal/orchestrator_service_pb2.py | 108 +++++----- .../internal/orchestrator_service_pb2.pyi | 134 ++++++++++-- dapr/ext/workflow/aio/dapr_workflow_client.py | 131 ++++++++++-- dapr/ext/workflow/dapr_workflow_client.py | 135 ++++++++++-- .../durabletask/test_client_routing.py | 195 ++++++++++++++++++ .../test_orchestration_executor.py | 16 +- tests/ext/workflow/test_workflow_client.py | 97 ++++++++- .../ext/workflow/test_workflow_client_aio.py | 103 ++++++++- tests/integration/apps/workflow_host.py | 57 +++++ tests/integration/conftest.py | 9 +- tests/integration/test_workflow_cross_app.py | 170 +++++++++++++++ tools/regen_durabletask_protos.sh | 71 +++++-- 24 files changed, 1431 insertions(+), 303 deletions(-) create mode 100644 tests/ext/workflow/durabletask/test_client_routing.py create mode 100644 tests/integration/apps/workflow_host.py create mode 100644 tests/integration/test_workflow_cross_app.py diff --git a/dapr/ext/workflow/_durabletask/aio/client.py b/dapr/ext/workflow/_durabletask/aio/client.py index a5da39b14..35f44c646 100644 --- a/dapr/ext/workflow/_durabletask/aio/client.py +++ b/dapr/ext/workflow/_durabletask/aio/client.py @@ -40,6 +40,7 @@ WorkflowState, _TransientTimeout, new_orchestration_state, + new_task_router, ) # If `opentelemetry-instrumentation-grpc` is available, enable the gRPC client interceptor @@ -114,6 +115,7 @@ async def schedule_new_orchestration( instance_id: Optional[str] = None, start_at: Optional[datetime] = None, reuse_id_policy: Optional[WorkflowIdReusePolicy] = None, + app_id: Optional[str] = None, ) -> str: name = orchestrator if isinstance(orchestrator, str) else task.get_name(orchestrator) @@ -125,6 +127,7 @@ async def schedule_new_orchestration( else None, scheduledStartTimestamp=helpers.new_timestamp(start_at) if start_at else None, version=helpers.get_string_value(None), + router=new_task_router(app_id), ) self._logger.info(f"Starting new '{name}' instance with ID = '{req.instanceId}'.") @@ -132,16 +135,33 @@ async def schedule_new_orchestration( return res.instanceId async def get_orchestration_state( - self, instance_id: str, *, fetch_payloads: bool = True + self, + instance_id: str, + *, + fetch_payloads: bool = True, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: - req = pb.GetInstanceRequest(instanceId=instance_id, getInputsAndOutputs=fetch_payloads) + req = pb.GetInstanceRequest( + instanceId=instance_id, + getInputsAndOutputs=fetch_payloads, + router=new_task_router(app_id), + ) res: pb.GetInstanceResponse = await self._get_stub().GetInstance(req) return new_orchestration_state(req.instanceId, res) async def wait_for_orchestration_start( - self, instance_id: str, *, fetch_payloads: bool = False, timeout: Optional[int] = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = False, + timeout: Optional[int] = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: - req = pb.GetInstanceRequest(instanceId=instance_id, getInputsAndOutputs=fetch_payloads) + req = pb.GetInstanceRequest( + instanceId=instance_id, + getInputsAndOutputs=fetch_payloads, + router=new_task_router(app_id), + ) self._logger.info( f"Waiting {'indefinitely' if timeout in (0, None) else f'up to {timeout}s'} for instance '{instance_id}' to start." ) @@ -158,9 +178,18 @@ async def _call(grpc_timeout): raise TimeoutError('Timed-out waiting for the orchestration to start') async def wait_for_orchestration_completion( - self, instance_id: str, *, fetch_payloads: bool = True, timeout: Optional[int] = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = True, + timeout: Optional[int] = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: - req = pb.GetInstanceRequest(instanceId=instance_id, getInputsAndOutputs=fetch_payloads) + req = pb.GetInstanceRequest( + instanceId=instance_id, + getInputsAndOutputs=fetch_payloads, + router=new_task_router(app_id), + ) self._logger.info( f"Waiting {'indefinitely' if timeout in (0, None) else f'up to {timeout}s'} for instance '{instance_id}' to complete." ) @@ -270,40 +299,78 @@ async def _call_with_transient_retry(self, instance_id, timeout, call_fn): raise _TransientTimeout() async def raise_orchestration_event( - self, instance_id: str, event_name: str, *, data: Optional[Any] = None + self, + instance_id: str, + event_name: str, + *, + data: Optional[Any] = None, + app_id: Optional[str] = None, ): req = pb.RaiseEventRequest( instanceId=instance_id, name=event_name, input=wrappers_pb2.StringValue(value=shared.to_json(data)) if data else None, + router=new_task_router(app_id), ) self._logger.info(f"Raising event '{event_name}' for instance '{instance_id}'.") await self._get_stub().RaiseEvent(req) async def terminate_orchestration( - self, instance_id: str, *, output: Optional[Any] = None, recursive: bool = True + self, + instance_id: str, + *, + output: Optional[Any] = None, + recursive: bool = True, + app_id: Optional[str] = None, ): req = pb.TerminateRequest( instanceId=instance_id, output=wrappers_pb2.StringValue(value=shared.to_json(output)) if output else None, recursive=recursive, + router=new_task_router(app_id), ) self._logger.info(f"Terminating instance '{instance_id}'.") await self._get_stub().TerminateInstance(req) - async def suspend_orchestration(self, instance_id: str): - req = pb.SuspendRequest(instanceId=instance_id) + async def suspend_orchestration( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ): + req = pb.SuspendRequest( + instanceId=instance_id, + router=new_task_router(app_id), + ) self._logger.info(f"Suspending instance '{instance_id}'.") await self._get_stub().SuspendInstance(req) - async def resume_orchestration(self, instance_id: str): - req = pb.ResumeRequest(instanceId=instance_id) + async def resume_orchestration( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ): + req = pb.ResumeRequest( + instanceId=instance_id, + router=new_task_router(app_id), + ) self._logger.info(f"Resuming instance '{instance_id}'.") await self._get_stub().ResumeInstance(req) - async def purge_orchestration(self, instance_id: str, recursive: bool = True): - req = pb.PurgeInstancesRequest(instanceId=instance_id, recursive=recursive) + async def purge_orchestration( + self, + instance_id: str, + recursive: bool = True, + *, + app_id: Optional[str] = None, + ): + req = pb.PurgeInstancesRequest( + instanceId=instance_id, + recursive=recursive, + router=new_task_router(app_id), + ) self._logger.info(f"Purging instance '{instance_id}'.") await self._get_stub().PurgeInstances(req) diff --git a/dapr/ext/workflow/_durabletask/client.py b/dapr/ext/workflow/_durabletask/client.py index 07e63d4a7..e3d11704d 100644 --- a/dapr/ext/workflow/_durabletask/client.py +++ b/dapr/ext/workflow/_durabletask/client.py @@ -109,6 +109,16 @@ def raise_if_failed(self): ) +def new_task_router(app_id: Optional[str]) -> Optional[pb.TaskRouter]: + """Builds a TaskRouter targeting another app, or None when no routing is requested. + + Only the target app ID is set; the sidecar stamps sourceAppID. + """ + if app_id is None: + return None + return pb.TaskRouter(targetAppID=app_id) + + class OrchestrationFailedError(Exception): def __init__(self, message: str, failure_details: task.FailureDetails): super().__init__(message) @@ -210,6 +220,7 @@ def schedule_new_orchestration( instance_id: Optional[str] = None, start_at: Optional[datetime] = None, reuse_id_policy: Optional[WorkflowIdReusePolicy] = None, + app_id: Optional[str] = None, ) -> str: name = orchestrator if isinstance(orchestrator, str) else task.get_name(orchestrator) @@ -223,6 +234,7 @@ def schedule_new_orchestration( input=input_pb, scheduledStartTimestamp=helpers.new_timestamp(start_at) if start_at else None, version=wrappers_pb2.StringValue(value=''), + router=new_task_router(app_id), ) self._logger.info(f"Starting new '{name}' instance with ID = '{req.instanceId}'.") @@ -230,16 +242,33 @@ def schedule_new_orchestration( return res.instanceId def get_orchestration_state( - self, instance_id: str, *, fetch_payloads: bool = True + self, + instance_id: str, + *, + fetch_payloads: bool = True, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: - req = pb.GetInstanceRequest(instanceId=instance_id, getInputsAndOutputs=fetch_payloads) + req = pb.GetInstanceRequest( + instanceId=instance_id, + getInputsAndOutputs=fetch_payloads, + router=new_task_router(app_id), + ) res: pb.GetInstanceResponse = self._stub.GetInstance(req) return new_orchestration_state(req.instanceId, res) def wait_for_orchestration_start( - self, instance_id: str, *, fetch_payloads: bool = False, timeout: Optional[int] = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = False, + timeout: Optional[int] = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: - req = pb.GetInstanceRequest(instanceId=instance_id, getInputsAndOutputs=fetch_payloads) + req = pb.GetInstanceRequest( + instanceId=instance_id, + getInputsAndOutputs=fetch_payloads, + router=new_task_router(app_id), + ) self._logger.info( f"Waiting {'indefinitely' if timeout in (0, None) else f'up to {timeout}s'} for instance '{instance_id}' to start." ) @@ -254,9 +283,18 @@ def _call(grpc_timeout): raise TimeoutError('Timed-out waiting for the orchestration to start') def wait_for_orchestration_completion( - self, instance_id: str, *, fetch_payloads: bool = True, timeout: Optional[int] = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = True, + timeout: Optional[int] = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: - req = pb.GetInstanceRequest(instanceId=instance_id, getInputsAndOutputs=fetch_payloads) + req = pb.GetInstanceRequest( + instanceId=instance_id, + getInputsAndOutputs=fetch_payloads, + router=new_task_router(app_id), + ) self._logger.info( f"Waiting {'indefinitely' if timeout in (0, None) else f'up to {timeout}s'} for instance '{instance_id}' to complete." ) @@ -393,40 +431,78 @@ def _call_with_transient_retry(self, instance_id, timeout, call_fn): raise _TransientTimeout() def raise_orchestration_event( - self, instance_id: str, event_name: str, *, data: Optional[Any] = None + self, + instance_id: str, + event_name: str, + *, + data: Optional[Any] = None, + app_id: Optional[str] = None, ): req = pb.RaiseEventRequest( instanceId=instance_id, name=event_name, input=wrappers_pb2.StringValue(value=shared.to_json(data)) if data else None, + router=new_task_router(app_id), ) self._logger.info(f"Raising event '{event_name}' for instance '{instance_id}'.") self._stub.RaiseEvent(req) def terminate_orchestration( - self, instance_id: str, *, output: Optional[Any] = None, recursive: bool = True + self, + instance_id: str, + *, + output: Optional[Any] = None, + recursive: bool = True, + app_id: Optional[str] = None, ): req = pb.TerminateRequest( instanceId=instance_id, output=wrappers_pb2.StringValue(value=shared.to_json(output)) if output else None, recursive=recursive, + router=new_task_router(app_id), ) self._logger.info(f"Terminating instance '{instance_id}'.") self._stub.TerminateInstance(req) - def suspend_orchestration(self, instance_id: str): - req = pb.SuspendRequest(instanceId=instance_id) + def suspend_orchestration( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ): + req = pb.SuspendRequest( + instanceId=instance_id, + router=new_task_router(app_id), + ) self._logger.info(f"Suspending instance '{instance_id}'.") self._stub.SuspendInstance(req) - def resume_orchestration(self, instance_id: str): - req = pb.ResumeRequest(instanceId=instance_id) + def resume_orchestration( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ): + req = pb.ResumeRequest( + instanceId=instance_id, + router=new_task_router(app_id), + ) self._logger.info(f"Resuming instance '{instance_id}'.") self._stub.ResumeInstance(req) - def purge_orchestration(self, instance_id: str, recursive: bool = True): - req = pb.PurgeInstancesRequest(instanceId=instance_id, recursive=recursive) + def purge_orchestration( + self, + instance_id: str, + recursive: bool = True, + *, + app_id: Optional[str] = None, + ): + req = pb.PurgeInstancesRequest( + instanceId=instance_id, + recursive=recursive, + router=new_task_router(app_id), + ) self._logger.info(f"Purging instance '{instance_id}'.") self._stub.PurgeInstances(req) diff --git a/dapr/ext/workflow/_durabletask/internal/PROTO_SOURCE_COMMIT_HASH b/dapr/ext/workflow/_durabletask/internal/PROTO_SOURCE_COMMIT_HASH index 08691e6da..41af5e2a0 100644 --- a/dapr/ext/workflow/_durabletask/internal/PROTO_SOURCE_COMMIT_HASH +++ b/dapr/ext/workflow/_durabletask/internal/PROTO_SOURCE_COMMIT_HASH @@ -1 +1 @@ -9d3681cb82a03aad057f361102d3a7e0ae638462 +f31a2a0523e01feda8f41cc22512ed70ee59b3ad diff --git a/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.py b/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.py index 7b43827ed..cae2467d1 100644 --- a/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.py +++ b/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.py @@ -28,7 +28,7 @@ from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x62\x61\x63kend_service.proto\x12\x1d\x64urabletask.protos.backend.v1\x1a\x13orchestration.proto\x1a\x14history_events.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"T\n\x0f\x41\x64\x64\x45ventRequest\x12#\n\x08instance\x18\x01 \x01(\x0b\x32\x11.WorkflowInstance\x12\x1c\n\x05\x65vent\x18\x02 \x01(\x0b\x32\r.HistoryEvent\"\x12\n\x10\x41\x64\x64\x45ventResponse\"`\n\x1f\x43ompleteActivityWorkItemRequest\x12\x17\n\x0f\x63ompletionToken\x18\x01 \x01(\t\x12$\n\rresponseEvent\x18\x02 \x01(\x0b\x32\r.HistoryEvent\"\"\n CompleteActivityWorkItemResponse\"\xa4\x03\n\x1f\x43ompleteWorkflowWorkItemRequest\x12\x17\n\x0f\x63ompletionToken\x18\x01 \x01(\t\x12#\n\x08instance\x18\x02 \x01(\x0b\x32\x11.WorkflowInstance\x12+\n\rruntimeStatus\x18\x03 \x01(\x0e\x32\x14.OrchestrationStatus\x12\x32\n\x0c\x63ustomStatus\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12!\n\nnewHistory\x18\x05 \x03(\x0b\x32\r.HistoryEvent\x12\x1f\n\x08newTasks\x18\x06 \x03(\x0b\x32\r.HistoryEvent\x12 \n\tnewTimers\x18\x07 \x03(\x0b\x32\r.HistoryEvent\x12\x43\n\x0bnewMessages\x18\x08 \x03(\x0b\x32..durabletask.protos.backend.v1.WorkflowMessage\x12\x37\n\x12numEventsProcessed\x18\t \x01(\x0b\x32\x1b.google.protobuf.Int32Value\"\"\n CompleteWorkflowWorkItemResponse\"T\n\x0fWorkflowMessage\x12#\n\x08instance\x18\x01 \x01(\x0b\x32\x11.WorkflowInstance\x12\x1c\n\x05\x65vent\x18\x02 \x01(\x0b\x32\r.HistoryEvent\"\x9c\x01\n\x14\x42\x61\x63kendWorkflowState\x12\x1c\n\x05inbox\x18\x01 \x03(\x0b\x32\r.HistoryEvent\x12\x1e\n\x07history\x18\x02 \x03(\x0b\x32\r.HistoryEvent\x12\x32\n\x0c\x63ustomStatus\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x12\n\ngeneration\x18\x04 \x01(\x04\"\x83\x01\n\x12\x41\x63tivityInvocation\x12#\n\x0chistoryEvent\x18\x01 \x01(\x0b\x32\r.HistoryEvent\x12\x32\n\x11propagatedHistory\x18\x02 \x01(\x0b\x32\x12.PropagatedHistoryH\x00\x88\x01\x01\x42\x14\n\x12_propagatedHistory\"\x9a\x01\n\x1d\x43reateWorkflowInstanceRequest\x12!\n\nstartEvent\x18\x01 \x01(\x0b\x32\r.HistoryEvent\x12\x32\n\x11propagatedHistory\x18\x03 \x01(\x0b\x32\x12.PropagatedHistoryH\x00\x88\x01\x01\x42\x14\n\x12_propagatedHistoryJ\x04\x08\x02\x10\x03R\x06policy\"\x94\x05\n\x10WorkflowMetadata\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12+\n\rruntimeStatus\x18\x03 \x01(\x0e\x32\x14.OrchestrationStatus\x12-\n\tcreatedAt\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x31\n\rlastUpdatedAt\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\x05input\x18\x06 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x32\n\x0c\x63ustomStatus\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\t \x01(\x0b\x32\x13.TaskFailureDetails\x12/\n\x0b\x63ompletedAt\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x18\n\x10parentInstanceId\x18\x0b \x01(\t\x12\x32\n\x07version\x18\x0c \x01(\x0b\x32\x1c.google.protobuf.StringValueH\x00\x88\x01\x01\x12\x36\n\x0bparentAppId\x18\r \x01(\x0b\x32\x1c.google.protobuf.StringValueH\x01\x88\x01\x01\x12\x32\n\tstartedAt\x18\x0e \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x02\x88\x01\x01\x42\n\n\x08_versionB\x0e\n\x0c_parentAppIdB\x0c\n\n_startedAt\"\xc3\x01\n\x1c\x42\x61\x63kendWorkflowStateMetadata\x12\x13\n\x0binboxLength\x18\x01 \x01(\x04\x12\x15\n\rhistoryLength\x18\x02 \x01(\x04\x12\x12\n\ngeneration\x18\x03 \x01(\x04\x12\x17\n\x0fsignatureLength\x18\x04 \x01(\x04\x12 \n\x18signingCertificateLength\x18\x05 \x01(\x04\x12(\n externalSigningCertificateLength\x18\x06 \x01(\x04\")\n\x12SigningCertificate\x12\x13\n\x0b\x63\x65rtificate\x18\x01 \x01(\x0c\"\xc4\x01\n\x10HistorySignature\x12\x17\n\x0fstartEventIndex\x18\x01 \x01(\x04\x12\x12\n\neventCount\x18\x02 \x01(\x04\x12$\n\x17previousSignatureDigest\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0c\x65ventsDigest\x18\x04 \x01(\x0c\x12\x18\n\x10\x63\x65rtificateIndex\x18\x05 \x01(\x04\x12\x11\n\tsignature\x18\x06 \x01(\x0c\x42\x1a\n\x18_previousSignatureDigest\"E\n\x0c\x44urableTimer\x12!\n\ntimerEvent\x18\x01 \x01(\x0b\x32\r.HistoryEvent\x12\x12\n\ngeneration\x18\x02 \x01(\x04\x42V\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15\x62\x61\x63kend_service.proto\x12\x1d\x64urabletask.protos.backend.v1\x1a\x13orchestration.proto\x1a\x14history_events.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"T\n\x0f\x41\x64\x64\x45ventRequest\x12#\n\x08instance\x18\x01 \x01(\x0b\x32\x11.WorkflowInstance\x12\x1c\n\x05\x65vent\x18\x02 \x01(\x0b\x32\r.HistoryEvent\"\x12\n\x10\x41\x64\x64\x45ventResponse\"`\n\x1f\x43ompleteActivityWorkItemRequest\x12\x17\n\x0f\x63ompletionToken\x18\x01 \x01(\t\x12$\n\rresponseEvent\x18\x02 \x01(\x0b\x32\r.HistoryEvent\"\"\n CompleteActivityWorkItemResponse\"\xa4\x03\n\x1f\x43ompleteWorkflowWorkItemRequest\x12\x17\n\x0f\x63ompletionToken\x18\x01 \x01(\t\x12#\n\x08instance\x18\x02 \x01(\x0b\x32\x11.WorkflowInstance\x12+\n\rruntimeStatus\x18\x03 \x01(\x0e\x32\x14.OrchestrationStatus\x12\x32\n\x0c\x63ustomStatus\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12!\n\nnewHistory\x18\x05 \x03(\x0b\x32\r.HistoryEvent\x12\x1f\n\x08newTasks\x18\x06 \x03(\x0b\x32\r.HistoryEvent\x12 \n\tnewTimers\x18\x07 \x03(\x0b\x32\r.HistoryEvent\x12\x43\n\x0bnewMessages\x18\x08 \x03(\x0b\x32..durabletask.protos.backend.v1.WorkflowMessage\x12\x37\n\x12numEventsProcessed\x18\t \x01(\x0b\x32\x1b.google.protobuf.Int32Value\"\"\n CompleteWorkflowWorkItemResponse\"T\n\x0fWorkflowMessage\x12#\n\x08instance\x18\x01 \x01(\x0b\x32\x11.WorkflowInstance\x12\x1c\n\x05\x65vent\x18\x02 \x01(\x0b\x32\r.HistoryEvent\"\x9c\x01\n\x14\x42\x61\x63kendWorkflowState\x12\x1c\n\x05inbox\x18\x01 \x03(\x0b\x32\r.HistoryEvent\x12\x1e\n\x07history\x18\x02 \x03(\x0b\x32\r.HistoryEvent\x12\x32\n\x0c\x63ustomStatus\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x12\n\ngeneration\x18\x04 \x01(\x04\"\x83\x01\n\x12\x41\x63tivityInvocation\x12#\n\x0chistoryEvent\x18\x01 \x01(\x0b\x32\r.HistoryEvent\x12\x32\n\x11propagatedHistory\x18\x02 \x01(\x0b\x32\x12.PropagatedHistoryH\x00\x88\x01\x01\x42\x14\n\x12_propagatedHistory\"\xbb\x01\n\x1d\x43reateWorkflowInstanceRequest\x12!\n\nstartEvent\x18\x01 \x01(\x0b\x32\r.HistoryEvent\x12\x32\n\x11propagatedHistory\x18\x03 \x01(\x0b\x32\x12.PropagatedHistoryH\x00\x88\x01\x01\x12\x1f\n\x17\x65nforceUniqueInstanceId\x18\x04 \x01(\x08\x42\x14\n\x12_propagatedHistoryJ\x04\x08\x02\x10\x03R\x06policy\"\x94\x05\n\x10WorkflowMetadata\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12+\n\rruntimeStatus\x18\x03 \x01(\x0e\x32\x14.OrchestrationStatus\x12-\n\tcreatedAt\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x31\n\rlastUpdatedAt\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\x05input\x18\x06 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x32\n\x0c\x63ustomStatus\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\t \x01(\x0b\x32\x13.TaskFailureDetails\x12/\n\x0b\x63ompletedAt\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x18\n\x10parentInstanceId\x18\x0b \x01(\t\x12\x32\n\x07version\x18\x0c \x01(\x0b\x32\x1c.google.protobuf.StringValueH\x00\x88\x01\x01\x12\x36\n\x0bparentAppId\x18\r \x01(\x0b\x32\x1c.google.protobuf.StringValueH\x01\x88\x01\x01\x12\x32\n\tstartedAt\x18\x0e \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x02\x88\x01\x01\x42\n\n\x08_versionB\x0e\n\x0c_parentAppIdB\x0c\n\n_startedAt\"\xc3\x01\n\x1c\x42\x61\x63kendWorkflowStateMetadata\x12\x13\n\x0binboxLength\x18\x01 \x01(\x04\x12\x15\n\rhistoryLength\x18\x02 \x01(\x04\x12\x12\n\ngeneration\x18\x03 \x01(\x04\x12\x17\n\x0fsignatureLength\x18\x04 \x01(\x04\x12 \n\x18signingCertificateLength\x18\x05 \x01(\x04\x12(\n externalSigningCertificateLength\x18\x06 \x01(\x04\")\n\x12SigningCertificate\x12\x13\n\x0b\x63\x65rtificate\x18\x01 \x01(\x0c\"\xc4\x01\n\x10HistorySignature\x12\x17\n\x0fstartEventIndex\x18\x01 \x01(\x04\x12\x12\n\neventCount\x18\x02 \x01(\x04\x12$\n\x17previousSignatureDigest\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0c\x65ventsDigest\x18\x04 \x01(\x0c\x12\x18\n\x10\x63\x65rtificateIndex\x18\x05 \x01(\x04\x12\x11\n\tsignature\x18\x06 \x01(\x0c\x42\x1a\n\x18_previousSignatureDigest\"E\n\x0c\x44urableTimer\x12!\n\ntimerEvent\x18\x01 \x01(\x0b\x32\r.HistoryEvent\x12\x12\n\ngeneration\x18\x02 \x01(\x04\x42V\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -55,15 +55,15 @@ _globals['_ACTIVITYINVOCATION']._serialized_start=1109 _globals['_ACTIVITYINVOCATION']._serialized_end=1240 _globals['_CREATEWORKFLOWINSTANCEREQUEST']._serialized_start=1243 - _globals['_CREATEWORKFLOWINSTANCEREQUEST']._serialized_end=1397 - _globals['_WORKFLOWMETADATA']._serialized_start=1400 - _globals['_WORKFLOWMETADATA']._serialized_end=2060 - _globals['_BACKENDWORKFLOWSTATEMETADATA']._serialized_start=2063 - _globals['_BACKENDWORKFLOWSTATEMETADATA']._serialized_end=2258 - _globals['_SIGNINGCERTIFICATE']._serialized_start=2260 - _globals['_SIGNINGCERTIFICATE']._serialized_end=2301 - _globals['_HISTORYSIGNATURE']._serialized_start=2304 - _globals['_HISTORYSIGNATURE']._serialized_end=2500 - _globals['_DURABLETIMER']._serialized_start=2502 - _globals['_DURABLETIMER']._serialized_end=2571 + _globals['_CREATEWORKFLOWINSTANCEREQUEST']._serialized_end=1430 + _globals['_WORKFLOWMETADATA']._serialized_start=1433 + _globals['_WORKFLOWMETADATA']._serialized_end=2093 + _globals['_BACKENDWORKFLOWSTATEMETADATA']._serialized_start=2096 + _globals['_BACKENDWORKFLOWSTATEMETADATA']._serialized_end=2291 + _globals['_SIGNINGCERTIFICATE']._serialized_start=2293 + _globals['_SIGNINGCERTIFICATE']._serialized_end=2334 + _globals['_HISTORYSIGNATURE']._serialized_start=2337 + _globals['_HISTORYSIGNATURE']._serialized_end=2533 + _globals['_DURABLETIMER']._serialized_start=2535 + _globals['_DURABLETIMER']._serialized_end=2604 # @@protoc_insertion_point(module_scope) diff --git a/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.pyi b/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.pyi index 08f6d2d58..c4d2739ab 100644 --- a/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.pyi +++ b/dapr/ext/workflow/_durabletask/internal/backend_service_pb2.pyi @@ -277,6 +277,12 @@ class CreateWorkflowInstanceRequest(_message.Message): STARTEVENT_FIELD_NUMBER: _builtins.int PROPAGATEDHISTORY_FIELD_NUMBER: _builtins.int + ENFORCEUNIQUEINSTANCEID_FIELD_NUMBER: _builtins.int + enforceUniqueInstanceId: _builtins.bool + """When true, the request fails with an ALREADY_EXISTS error if a workflow + instance with the same instanceId already exists, whether active or + completed. When false, an existing completed instance is restarted. + """ @_builtins.property def startEvent(self) -> _history_events_pb2.HistoryEvent: ... @_builtins.property @@ -288,10 +294,11 @@ class CreateWorkflowInstanceRequest(_message.Message): *, startEvent: _history_events_pb2.HistoryEvent | None = ..., propagatedHistory: _history_events_pb2.PropagatedHistory | None = ..., + enforceUniqueInstanceId: _builtins.bool = ..., ) -> None: ... _HasFieldArgType: _TypeAlias = _typing.Literal["_propagatedHistory", b"_propagatedHistory", "propagatedHistory", b"propagatedHistory", "startEvent", b"startEvent"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["_propagatedHistory", b"_propagatedHistory", "propagatedHistory", b"propagatedHistory", "startEvent", b"startEvent"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_propagatedHistory", b"_propagatedHistory", "enforceUniqueInstanceId", b"enforceUniqueInstanceId", "propagatedHistory", b"propagatedHistory", "startEvent", b"startEvent"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... _WhichOneofReturnType__propagatedHistory: _TypeAlias = _typing.Literal["propagatedHistory"] # noqa: Y015 _WhichOneofArgType__propagatedHistory: _TypeAlias = _typing.Literal["_propagatedHistory", b"_propagatedHistory"] # noqa: Y015 diff --git a/dapr/ext/workflow/_durabletask/internal/helpers.py b/dapr/ext/workflow/_durabletask/internal/helpers.py index 387a9ee10..56ab04461 100644 --- a/dapr/ext/workflow/_durabletask/internal/helpers.py +++ b/dapr/ext/workflow/_durabletask/internal/helpers.py @@ -200,10 +200,11 @@ def new_schedule_task_action( task_execution_id: str = '', propagation_scope: Optional[int] = None, ) -> pb.WorkflowAction: + # Routing is carried by the enclosing WorkflowAction.router; the inner + # ScheduleTaskAction router field is reserved in the protos. schedule = pb.ScheduleTaskAction( name=name, input=get_string_value(encoded_input), - router=router, taskExecutionId=task_execution_id, ) if propagation_scope is not None: @@ -229,11 +230,12 @@ def new_create_child_workflow_action( router: Optional[pb.TaskRouter] = None, propagation_scope: Optional[int] = None, ) -> pb.WorkflowAction: + # Routing is carried by the enclosing WorkflowAction.router; the inner + # CreateChildWorkflowAction router field is reserved in the protos. child = pb.CreateChildWorkflowAction( name=name, instanceId=instance_id, input=get_string_value(encoded_input), - router=router, ) if propagation_scope is not None: child.historyPropagationScope = propagation_scope diff --git a/dapr/ext/workflow/_durabletask/internal/history_events_pb2.py b/dapr/ext/workflow/_durabletask/internal/history_events_pb2.py index b70c3a5f5..472616d37 100644 --- a/dapr/ext/workflow/_durabletask/internal/history_events_pb2.py +++ b/dapr/ext/workflow/_durabletask/internal/history_events_pb2.py @@ -28,7 +28,7 @@ from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14history_events.proto\x1a\x13orchestration.proto\x1a\x11\x61ttestation.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xd6\x03\n\x15\x45xecutionStartedEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x10workflowInstance\x18\x04 \x01(\x0b\x32\x11.WorkflowInstance\x12+\n\x0eparentInstance\x18\x05 \x01(\x0b\x32\x13.ParentInstanceInfo\x12;\n\x17scheduledStartTimestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12)\n\x12parentTraceContext\x18\x07 \x01(\x0b\x32\r.TraceContext\x12\x34\n\x0eworkflowSpanID\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12.\n\x04tags\x18\t \x03(\x0b\x32 .ExecutionStartedEvent.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xa2\x01\n\x17\x45xecutionCompletedEvent\x12,\n\x0eworkflowStatus\x18\x01 \x01(\x0e\x32\x14.OrchestrationStatus\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\x03 \x01(\x0b\x32\x13.TaskFailureDetails\"X\n\x18\x45xecutionTerminatedEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x0f\n\x07recurse\x18\x02 \x01(\x08\"\xfa\x02\n\x12TaskScheduledEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12)\n\x12parentTraceContext\x18\x04 \x01(\x0b\x32\r.TraceContext\x12\x17\n\x0ftaskExecutionId\x18\x05 \x01(\t\x12>\n\x17rerunParentInstanceInfo\x18\x06 \x01(\x0b\x32\x18.RerunParentInstanceInfoH\x00\x88\x01\x01\x12>\n\x17historyPropagationScope\x18\x07 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x01\x88\x01\x01\x42\x1a\n\x18_rerunParentInstanceInfoB\x1a\n\x18_historyPropagationScope\"\xf4\x01\n\x12TaskCompletedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x17\n\x0ftaskExecutionId\x18\x03 \x01(\t\x12\x38\n\x0b\x61ttestation\x18\x04 \x01(\x0b\x32\x1e.ActivityCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\"\xf0\x01\n\x0fTaskFailedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12+\n\x0e\x66\x61ilureDetails\x18\x02 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x17\n\x0ftaskExecutionId\x18\x03 \x01(\t\x12\x38\n\x0b\x61ttestation\x18\x04 \x01(\x0b\x32\x1e.ActivityCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\"\x84\x03\n!ChildWorkflowInstanceCreatedEvent\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12)\n\x12parentTraceContext\x18\x05 \x01(\x0b\x32\r.TraceContext\x12>\n\x17rerunParentInstanceInfo\x18\x06 \x01(\x0b\x32\x18.RerunParentInstanceInfoH\x00\x88\x01\x01\x12>\n\x17historyPropagationScope\x18\x07 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x01\x88\x01\x01\x42\x1a\n\x18_rerunParentInstanceInfoB\x1a\n\x18_historyPropagationScope\"\xe9\x01\n#ChildWorkflowInstanceCompletedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x35\n\x0b\x61ttestation\x18\x03 \x01(\x0b\x32\x1b.ChildCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\"\xe5\x01\n ChildWorkflowInstanceFailedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12+\n\x0e\x66\x61ilureDetails\x18\x02 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x35\n\x0b\x61ttestation\x18\x03 \x01(\x0b\x32\x1b.ChildCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\":\n$DetachedWorkflowInstanceCreatedEvent\x12\x12\n\ninstanceId\x18\x01 \x01(\t\"\x18\n\x16TimerOriginCreateTimer\"(\n\x18TimerOriginExternalEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\"3\n\x18TimerOriginActivityRetry\x12\x17\n\x0ftaskExecutionId\x18\x01 \x01(\t\"3\n\x1dTimerOriginChildWorkflowRetry\x12\x12\n\ninstanceId\x18\x01 \x01(\t\"\x97\x03\n\x11TimerCreatedEvent\x12*\n\x06\x66ireAt\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x11\n\x04name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12>\n\x17rerunParentInstanceInfo\x18\x03 \x01(\x0b\x32\x18.RerunParentInstanceInfoH\x02\x88\x01\x01\x12.\n\x0b\x63reateTimer\x18\x04 \x01(\x0b\x32\x17.TimerOriginCreateTimerH\x00\x12\x32\n\rexternalEvent\x18\x05 \x01(\x0b\x32\x19.TimerOriginExternalEventH\x00\x12\x32\n\ractivityRetry\x18\x06 \x01(\x0b\x32\x19.TimerOriginActivityRetryH\x00\x12<\n\x12\x63hildWorkflowRetry\x18\x07 \x01(\x0b\x32\x1e.TimerOriginChildWorkflowRetryH\x00\x42\x08\n\x06originB\x07\n\x05_nameB\x1a\n\x18_rerunParentInstanceInfo\"N\n\x0fTimerFiredEvent\x12*\n\x06\x66ireAt\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0f\n\x07timerId\x18\x02 \x01(\x05\"J\n\x14WorkflowStartedEvent\x12&\n\x07version\x18\x01 \x01(\x0b\x32\x10.WorkflowVersionH\x00\x88\x01\x01\x42\n\n\x08_version\"\x18\n\x16WorkflowCompletedEvent\"_\n\x0e\x45ventSentEvent\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"M\n\x10\x45ventRaisedEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12+\n\x05input\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"A\n\x12\x43ontinueAsNewEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"F\n\x17\x45xecutionSuspendedEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"D\n\x15\x45xecutionResumedEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"a\n\x15\x45xecutionStalledEvent\x12\x1e\n\x06reason\x18\x01 \x01(\x0e\x32\x0e.StalledReason\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_description\"\xfa\t\n\x0cHistoryEvent\x12\x0f\n\x07\x65ventId\x18\x01 \x01(\x05\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x32\n\x10\x65xecutionStarted\x18\x03 \x01(\x0b\x32\x16.ExecutionStartedEventH\x00\x12\x36\n\x12\x65xecutionCompleted\x18\x04 \x01(\x0b\x32\x18.ExecutionCompletedEventH\x00\x12\x38\n\x13\x65xecutionTerminated\x18\x05 \x01(\x0b\x32\x19.ExecutionTerminatedEventH\x00\x12,\n\rtaskScheduled\x18\x06 \x01(\x0b\x32\x13.TaskScheduledEventH\x00\x12,\n\rtaskCompleted\x18\x07 \x01(\x0b\x32\x13.TaskCompletedEventH\x00\x12&\n\ntaskFailed\x18\x08 \x01(\x0b\x32\x10.TaskFailedEventH\x00\x12J\n\x1c\x63hildWorkflowInstanceCreated\x18\t \x01(\x0b\x32\".ChildWorkflowInstanceCreatedEventH\x00\x12N\n\x1e\x63hildWorkflowInstanceCompleted\x18\n \x01(\x0b\x32$.ChildWorkflowInstanceCompletedEventH\x00\x12H\n\x1b\x63hildWorkflowInstanceFailed\x18\x0b \x01(\x0b\x32!.ChildWorkflowInstanceFailedEventH\x00\x12*\n\x0ctimerCreated\x18\x0c \x01(\x0b\x32\x12.TimerCreatedEventH\x00\x12&\n\ntimerFired\x18\r \x01(\x0b\x32\x10.TimerFiredEventH\x00\x12\x30\n\x0fworkflowStarted\x18\x0e \x01(\x0b\x32\x15.WorkflowStartedEventH\x00\x12\x34\n\x11workflowCompleted\x18\x0f \x01(\x0b\x32\x17.WorkflowCompletedEventH\x00\x12$\n\teventSent\x18\x10 \x01(\x0b\x32\x0f.EventSentEventH\x00\x12(\n\x0b\x65ventRaised\x18\x11 \x01(\x0b\x32\x11.EventRaisedEventH\x00\x12,\n\rcontinueAsNew\x18\x14 \x01(\x0b\x32\x13.ContinueAsNewEventH\x00\x12\x36\n\x12\x65xecutionSuspended\x18\x15 \x01(\x0b\x32\x18.ExecutionSuspendedEventH\x00\x12\x32\n\x10\x65xecutionResumed\x18\x16 \x01(\x0b\x32\x16.ExecutionResumedEventH\x00\x12\x32\n\x10\x65xecutionStalled\x18\x1f \x01(\x0b\x32\x16.ExecutionStalledEventH\x00\x12P\n\x1f\x64\x65tachedWorkflowInstanceCreated\x18 \x01(\x0b\x32%.DetachedWorkflowInstanceCreatedEventH\x00\x12 \n\x06router\x18\x1e \x01(\x0b\x32\x0b.TaskRouterH\x01\x88\x01\x01\x42\x0b\n\teventTypeB\t\n\x07_routerJ\x04\x08\x12\x10\x13J\x04\x08\x13\x10\x14J\x04\x08\x17\x10\x18J\x04\x08\x18\x10\x19J\x04\x08\x19\x10\x1aJ\x04\x08\x1a\x10\x1bJ\x04\x08\x1b\x10\x1cJ\x04\x08\x1c\x10\x1dJ\x04\x08\x1d\x10\x1e\"\x96\x01\n\x16PropagatedHistoryChunk\x12\x11\n\trawEvents\x18\x01 \x03(\x0c\x12\r\n\x05\x61ppId\x18\x02 \x01(\t\x12\x12\n\ninstanceId\x18\x03 \x01(\t\x12\x14\n\x0cworkflowName\x18\x04 \x01(\t\x12\x15\n\rrawSignatures\x18\x05 \x03(\x0c\x12\x19\n\x11signingCertChains\x18\x06 \x03(\x0c\"e\n\x11PropagatedHistory\x12\'\n\x05scope\x18\x01 \x01(\x0e\x32\x18.HistoryPropagationScope\x12\'\n\x06\x63hunks\x18\x02 \x03(\x0b\x32\x17.PropagatedHistoryChunkBV\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14history_events.proto\x1a\x13orchestration.proto\x1a\x11\x61ttestation.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xd6\x03\n\x15\x45xecutionStartedEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x10workflowInstance\x18\x04 \x01(\x0b\x32\x11.WorkflowInstance\x12+\n\x0eparentInstance\x18\x05 \x01(\x0b\x32\x13.ParentInstanceInfo\x12;\n\x17scheduledStartTimestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12)\n\x12parentTraceContext\x18\x07 \x01(\x0b\x32\r.TraceContext\x12\x34\n\x0eworkflowSpanID\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12.\n\x04tags\x18\t \x03(\x0b\x32 .ExecutionStartedEvent.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xa2\x01\n\x17\x45xecutionCompletedEvent\x12,\n\x0eworkflowStatus\x18\x01 \x01(\x0e\x32\x14.OrchestrationStatus\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\x03 \x01(\x0b\x32\x13.TaskFailureDetails\"X\n\x18\x45xecutionTerminatedEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x0f\n\x07recurse\x18\x02 \x01(\x08\"\xfa\x02\n\x12TaskScheduledEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12)\n\x12parentTraceContext\x18\x04 \x01(\x0b\x32\r.TraceContext\x12\x17\n\x0ftaskExecutionId\x18\x05 \x01(\t\x12>\n\x17rerunParentInstanceInfo\x18\x06 \x01(\x0b\x32\x18.RerunParentInstanceInfoH\x00\x88\x01\x01\x12>\n\x17historyPropagationScope\x18\x07 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x01\x88\x01\x01\x42\x1a\n\x18_rerunParentInstanceInfoB\x1a\n\x18_historyPropagationScope\"\xf4\x01\n\x12TaskCompletedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x17\n\x0ftaskExecutionId\x18\x03 \x01(\t\x12\x38\n\x0b\x61ttestation\x18\x04 \x01(\x0b\x32\x1e.ActivityCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\"\xf0\x01\n\x0fTaskFailedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12+\n\x0e\x66\x61ilureDetails\x18\x02 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x17\n\x0ftaskExecutionId\x18\x03 \x01(\t\x12\x38\n\x0b\x61ttestation\x18\x04 \x01(\x0b\x32\x1e.ActivityCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\"\xe0\x03\n!ChildWorkflowInstanceCreatedEvent\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12)\n\x12parentTraceContext\x18\x05 \x01(\x0b\x32\r.TraceContext\x12>\n\x17rerunParentInstanceInfo\x18\x06 \x01(\x0b\x32\x18.RerunParentInstanceInfoH\x00\x88\x01\x01\x12>\n\x17historyPropagationScope\x18\x07 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x01\x88\x01\x01\x12>\n\x17retryParentInstanceInfo\x18\x08 \x01(\x0b\x32\x18.RetryParentInstanceInfoH\x02\x88\x01\x01\x42\x1a\n\x18_rerunParentInstanceInfoB\x1a\n\x18_historyPropagationScopeB\x1a\n\x18_retryParentInstanceInfo\"\xe9\x01\n#ChildWorkflowInstanceCompletedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x35\n\x0b\x61ttestation\x18\x03 \x01(\x0b\x32\x1b.ChildCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\"\xe5\x01\n ChildWorkflowInstanceFailedEvent\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12+\n\x0e\x66\x61ilureDetails\x18\x02 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x35\n\x0b\x61ttestation\x18\x03 \x01(\x0b\x32\x1b.ChildCompletionAttestationH\x00\x88\x01\x01\x12\x1e\n\x11signerCertificate\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_attestationB\x14\n\x12_signerCertificate\":\n$DetachedWorkflowInstanceCreatedEvent\x12\x12\n\ninstanceId\x18\x01 \x01(\t\"\x18\n\x16TimerOriginCreateTimer\"(\n\x18TimerOriginExternalEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\"3\n\x18TimerOriginActivityRetry\x12\x17\n\x0ftaskExecutionId\x18\x01 \x01(\t\"3\n\x1dTimerOriginChildWorkflowRetry\x12\x12\n\ninstanceId\x18\x01 \x01(\t\"\x97\x03\n\x11TimerCreatedEvent\x12*\n\x06\x66ireAt\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x11\n\x04name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12>\n\x17rerunParentInstanceInfo\x18\x03 \x01(\x0b\x32\x18.RerunParentInstanceInfoH\x02\x88\x01\x01\x12.\n\x0b\x63reateTimer\x18\x04 \x01(\x0b\x32\x17.TimerOriginCreateTimerH\x00\x12\x32\n\rexternalEvent\x18\x05 \x01(\x0b\x32\x19.TimerOriginExternalEventH\x00\x12\x32\n\ractivityRetry\x18\x06 \x01(\x0b\x32\x19.TimerOriginActivityRetryH\x00\x12<\n\x12\x63hildWorkflowRetry\x18\x07 \x01(\x0b\x32\x1e.TimerOriginChildWorkflowRetryH\x00\x42\x08\n\x06originB\x07\n\x05_nameB\x1a\n\x18_rerunParentInstanceInfo\"N\n\x0fTimerFiredEvent\x12*\n\x06\x66ireAt\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0f\n\x07timerId\x18\x02 \x01(\x05\"J\n\x14WorkflowStartedEvent\x12&\n\x07version\x18\x01 \x01(\x0b\x32\x10.WorkflowVersionH\x00\x88\x01\x01\x42\n\n\x08_version\"\x18\n\x16WorkflowCompletedEvent\"_\n\x0e\x45ventSentEvent\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"M\n\x10\x45ventRaisedEvent\x12\x0c\n\x04name\x18\x01 \x01(\t\x12+\n\x05input\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"A\n\x12\x43ontinueAsNewEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"F\n\x17\x45xecutionSuspendedEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"D\n\x15\x45xecutionResumedEvent\x12+\n\x05input\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"a\n\x15\x45xecutionStalledEvent\x12\x1e\n\x06reason\x18\x01 \x01(\x0e\x32\x0e.StalledReason\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_description\"\xfa\t\n\x0cHistoryEvent\x12\x0f\n\x07\x65ventId\x18\x01 \x01(\x05\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x32\n\x10\x65xecutionStarted\x18\x03 \x01(\x0b\x32\x16.ExecutionStartedEventH\x00\x12\x36\n\x12\x65xecutionCompleted\x18\x04 \x01(\x0b\x32\x18.ExecutionCompletedEventH\x00\x12\x38\n\x13\x65xecutionTerminated\x18\x05 \x01(\x0b\x32\x19.ExecutionTerminatedEventH\x00\x12,\n\rtaskScheduled\x18\x06 \x01(\x0b\x32\x13.TaskScheduledEventH\x00\x12,\n\rtaskCompleted\x18\x07 \x01(\x0b\x32\x13.TaskCompletedEventH\x00\x12&\n\ntaskFailed\x18\x08 \x01(\x0b\x32\x10.TaskFailedEventH\x00\x12J\n\x1c\x63hildWorkflowInstanceCreated\x18\t \x01(\x0b\x32\".ChildWorkflowInstanceCreatedEventH\x00\x12N\n\x1e\x63hildWorkflowInstanceCompleted\x18\n \x01(\x0b\x32$.ChildWorkflowInstanceCompletedEventH\x00\x12H\n\x1b\x63hildWorkflowInstanceFailed\x18\x0b \x01(\x0b\x32!.ChildWorkflowInstanceFailedEventH\x00\x12*\n\x0ctimerCreated\x18\x0c \x01(\x0b\x32\x12.TimerCreatedEventH\x00\x12&\n\ntimerFired\x18\r \x01(\x0b\x32\x10.TimerFiredEventH\x00\x12\x30\n\x0fworkflowStarted\x18\x0e \x01(\x0b\x32\x15.WorkflowStartedEventH\x00\x12\x34\n\x11workflowCompleted\x18\x0f \x01(\x0b\x32\x17.WorkflowCompletedEventH\x00\x12$\n\teventSent\x18\x10 \x01(\x0b\x32\x0f.EventSentEventH\x00\x12(\n\x0b\x65ventRaised\x18\x11 \x01(\x0b\x32\x11.EventRaisedEventH\x00\x12,\n\rcontinueAsNew\x18\x14 \x01(\x0b\x32\x13.ContinueAsNewEventH\x00\x12\x36\n\x12\x65xecutionSuspended\x18\x15 \x01(\x0b\x32\x18.ExecutionSuspendedEventH\x00\x12\x32\n\x10\x65xecutionResumed\x18\x16 \x01(\x0b\x32\x16.ExecutionResumedEventH\x00\x12\x32\n\x10\x65xecutionStalled\x18\x1f \x01(\x0b\x32\x16.ExecutionStalledEventH\x00\x12P\n\x1f\x64\x65tachedWorkflowInstanceCreated\x18 \x01(\x0b\x32%.DetachedWorkflowInstanceCreatedEventH\x00\x12 \n\x06router\x18\x1e \x01(\x0b\x32\x0b.TaskRouterH\x01\x88\x01\x01\x42\x0b\n\teventTypeB\t\n\x07_routerJ\x04\x08\x12\x10\x13J\x04\x08\x13\x10\x14J\x04\x08\x17\x10\x18J\x04\x08\x18\x10\x19J\x04\x08\x19\x10\x1aJ\x04\x08\x1a\x10\x1bJ\x04\x08\x1b\x10\x1cJ\x04\x08\x1c\x10\x1dJ\x04\x08\x1d\x10\x1e\"\x96\x01\n\x16PropagatedHistoryChunk\x12\x11\n\trawEvents\x18\x01 \x03(\x0c\x12\r\n\x05\x61ppId\x18\x02 \x01(\t\x12\x12\n\ninstanceId\x18\x03 \x01(\t\x12\x14\n\x0cworkflowName\x18\x04 \x01(\t\x12\x15\n\rrawSignatures\x18\x05 \x03(\x0c\x12\x19\n\x11signingCertChains\x18\x06 \x03(\x0c\"e\n\x11PropagatedHistory\x12\'\n\x05scope\x18\x01 \x01(\x0e\x32\x18.HistoryPropagationScope\x12\'\n\x06\x63hunks\x18\x02 \x03(\x0b\x32\x17.PropagatedHistoryChunkBV\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -53,45 +53,45 @@ _globals['_TASKFAILEDEVENT']._serialized_start=1486 _globals['_TASKFAILEDEVENT']._serialized_end=1726 _globals['_CHILDWORKFLOWINSTANCECREATEDEVENT']._serialized_start=1729 - _globals['_CHILDWORKFLOWINSTANCECREATEDEVENT']._serialized_end=2117 - _globals['_CHILDWORKFLOWINSTANCECOMPLETEDEVENT']._serialized_start=2120 - _globals['_CHILDWORKFLOWINSTANCECOMPLETEDEVENT']._serialized_end=2353 - _globals['_CHILDWORKFLOWINSTANCEFAILEDEVENT']._serialized_start=2356 - _globals['_CHILDWORKFLOWINSTANCEFAILEDEVENT']._serialized_end=2585 - _globals['_DETACHEDWORKFLOWINSTANCECREATEDEVENT']._serialized_start=2587 - _globals['_DETACHEDWORKFLOWINSTANCECREATEDEVENT']._serialized_end=2645 - _globals['_TIMERORIGINCREATETIMER']._serialized_start=2647 - _globals['_TIMERORIGINCREATETIMER']._serialized_end=2671 - _globals['_TIMERORIGINEXTERNALEVENT']._serialized_start=2673 - _globals['_TIMERORIGINEXTERNALEVENT']._serialized_end=2713 - _globals['_TIMERORIGINACTIVITYRETRY']._serialized_start=2715 - _globals['_TIMERORIGINACTIVITYRETRY']._serialized_end=2766 - _globals['_TIMERORIGINCHILDWORKFLOWRETRY']._serialized_start=2768 - _globals['_TIMERORIGINCHILDWORKFLOWRETRY']._serialized_end=2819 - _globals['_TIMERCREATEDEVENT']._serialized_start=2822 - _globals['_TIMERCREATEDEVENT']._serialized_end=3229 - _globals['_TIMERFIREDEVENT']._serialized_start=3231 - _globals['_TIMERFIREDEVENT']._serialized_end=3309 - _globals['_WORKFLOWSTARTEDEVENT']._serialized_start=3311 - _globals['_WORKFLOWSTARTEDEVENT']._serialized_end=3385 - _globals['_WORKFLOWCOMPLETEDEVENT']._serialized_start=3387 - _globals['_WORKFLOWCOMPLETEDEVENT']._serialized_end=3411 - _globals['_EVENTSENTEVENT']._serialized_start=3413 - _globals['_EVENTSENTEVENT']._serialized_end=3508 - _globals['_EVENTRAISEDEVENT']._serialized_start=3510 - _globals['_EVENTRAISEDEVENT']._serialized_end=3587 - _globals['_CONTINUEASNEWEVENT']._serialized_start=3589 - _globals['_CONTINUEASNEWEVENT']._serialized_end=3654 - _globals['_EXECUTIONSUSPENDEDEVENT']._serialized_start=3656 - _globals['_EXECUTIONSUSPENDEDEVENT']._serialized_end=3726 - _globals['_EXECUTIONRESUMEDEVENT']._serialized_start=3728 - _globals['_EXECUTIONRESUMEDEVENT']._serialized_end=3796 - _globals['_EXECUTIONSTALLEDEVENT']._serialized_start=3798 - _globals['_EXECUTIONSTALLEDEVENT']._serialized_end=3895 - _globals['_HISTORYEVENT']._serialized_start=3898 - _globals['_HISTORYEVENT']._serialized_end=5172 - _globals['_PROPAGATEDHISTORYCHUNK']._serialized_start=5175 - _globals['_PROPAGATEDHISTORYCHUNK']._serialized_end=5325 - _globals['_PROPAGATEDHISTORY']._serialized_start=5327 - _globals['_PROPAGATEDHISTORY']._serialized_end=5428 + _globals['_CHILDWORKFLOWINSTANCECREATEDEVENT']._serialized_end=2209 + _globals['_CHILDWORKFLOWINSTANCECOMPLETEDEVENT']._serialized_start=2212 + _globals['_CHILDWORKFLOWINSTANCECOMPLETEDEVENT']._serialized_end=2445 + _globals['_CHILDWORKFLOWINSTANCEFAILEDEVENT']._serialized_start=2448 + _globals['_CHILDWORKFLOWINSTANCEFAILEDEVENT']._serialized_end=2677 + _globals['_DETACHEDWORKFLOWINSTANCECREATEDEVENT']._serialized_start=2679 + _globals['_DETACHEDWORKFLOWINSTANCECREATEDEVENT']._serialized_end=2737 + _globals['_TIMERORIGINCREATETIMER']._serialized_start=2739 + _globals['_TIMERORIGINCREATETIMER']._serialized_end=2763 + _globals['_TIMERORIGINEXTERNALEVENT']._serialized_start=2765 + _globals['_TIMERORIGINEXTERNALEVENT']._serialized_end=2805 + _globals['_TIMERORIGINACTIVITYRETRY']._serialized_start=2807 + _globals['_TIMERORIGINACTIVITYRETRY']._serialized_end=2858 + _globals['_TIMERORIGINCHILDWORKFLOWRETRY']._serialized_start=2860 + _globals['_TIMERORIGINCHILDWORKFLOWRETRY']._serialized_end=2911 + _globals['_TIMERCREATEDEVENT']._serialized_start=2914 + _globals['_TIMERCREATEDEVENT']._serialized_end=3321 + _globals['_TIMERFIREDEVENT']._serialized_start=3323 + _globals['_TIMERFIREDEVENT']._serialized_end=3401 + _globals['_WORKFLOWSTARTEDEVENT']._serialized_start=3403 + _globals['_WORKFLOWSTARTEDEVENT']._serialized_end=3477 + _globals['_WORKFLOWCOMPLETEDEVENT']._serialized_start=3479 + _globals['_WORKFLOWCOMPLETEDEVENT']._serialized_end=3503 + _globals['_EVENTSENTEVENT']._serialized_start=3505 + _globals['_EVENTSENTEVENT']._serialized_end=3600 + _globals['_EVENTRAISEDEVENT']._serialized_start=3602 + _globals['_EVENTRAISEDEVENT']._serialized_end=3679 + _globals['_CONTINUEASNEWEVENT']._serialized_start=3681 + _globals['_CONTINUEASNEWEVENT']._serialized_end=3746 + _globals['_EXECUTIONSUSPENDEDEVENT']._serialized_start=3748 + _globals['_EXECUTIONSUSPENDEDEVENT']._serialized_end=3818 + _globals['_EXECUTIONRESUMEDEVENT']._serialized_start=3820 + _globals['_EXECUTIONRESUMEDEVENT']._serialized_end=3888 + _globals['_EXECUTIONSTALLEDEVENT']._serialized_start=3890 + _globals['_EXECUTIONSTALLEDEVENT']._serialized_end=3987 + _globals['_HISTORYEVENT']._serialized_start=3990 + _globals['_HISTORYEVENT']._serialized_end=5264 + _globals['_PROPAGATEDHISTORYCHUNK']._serialized_start=5267 + _globals['_PROPAGATEDHISTORYCHUNK']._serialized_end=5417 + _globals['_PROPAGATEDHISTORY']._serialized_start=5419 + _globals['_PROPAGATEDHISTORY']._serialized_end=5520 # @@protoc_insertion_point(module_scope) diff --git a/dapr/ext/workflow/_durabletask/internal/history_events_pb2.pyi b/dapr/ext/workflow/_durabletask/internal/history_events_pb2.pyi index c2676d8a7..e4e066155 100644 --- a/dapr/ext/workflow/_durabletask/internal/history_events_pb2.pyi +++ b/dapr/ext/workflow/_durabletask/internal/history_events_pb2.pyi @@ -303,6 +303,7 @@ class ChildWorkflowInstanceCreatedEvent(_message.Message): PARENTTRACECONTEXT_FIELD_NUMBER: _builtins.int RERUNPARENTINSTANCEINFO_FIELD_NUMBER: _builtins.int HISTORYPROPAGATIONSCOPE_FIELD_NUMBER: _builtins.int + RETRYPARENTINSTANCEINFO_FIELD_NUMBER: _builtins.int instanceId: _builtins.str name: _builtins.str historyPropagationScope: _orchestration_pb2.HistoryPropagationScope.ValueType @@ -322,6 +323,15 @@ class ChildWorkflowInstanceCreatedEvent(_message.Message): workflow execution as the result of a rerun operation. """ + @_builtins.property + def retryParentInstanceInfo(self) -> _orchestration_pb2.RetryParentInstanceInfo: + """If defined, indicates that this child workflow is a retry attempt and + links it back to the first attempt in the retry chain. Absent on the + first attempt. Consumers correlate retry attempts by grouping on + retryParentInstanceInfo.instanceID when present, otherwise on this + event's own instanceId. + """ + def __init__( self, *, @@ -332,19 +342,24 @@ class ChildWorkflowInstanceCreatedEvent(_message.Message): parentTraceContext: _orchestration_pb2.TraceContext | None = ..., rerunParentInstanceInfo: _orchestration_pb2.RerunParentInstanceInfo | None = ..., historyPropagationScope: _orchestration_pb2.HistoryPropagationScope.ValueType | None = ..., + retryParentInstanceInfo: _orchestration_pb2.RetryParentInstanceInfo | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_rerunParentInstanceInfo", b"_rerunParentInstanceInfo", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "parentTraceContext", b"parentTraceContext", "rerunParentInstanceInfo", b"rerunParentInstanceInfo", "version", b"version"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_rerunParentInstanceInfo", b"_rerunParentInstanceInfo", "_retryParentInstanceInfo", b"_retryParentInstanceInfo", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "parentTraceContext", b"parentTraceContext", "rerunParentInstanceInfo", b"rerunParentInstanceInfo", "retryParentInstanceInfo", b"retryParentInstanceInfo", "version", b"version"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_rerunParentInstanceInfo", b"_rerunParentInstanceInfo", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "instanceId", b"instanceId", "name", b"name", "parentTraceContext", b"parentTraceContext", "rerunParentInstanceInfo", b"rerunParentInstanceInfo", "version", b"version"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_rerunParentInstanceInfo", b"_rerunParentInstanceInfo", "_retryParentInstanceInfo", b"_retryParentInstanceInfo", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "instanceId", b"instanceId", "name", b"name", "parentTraceContext", b"parentTraceContext", "rerunParentInstanceInfo", b"rerunParentInstanceInfo", "retryParentInstanceInfo", b"retryParentInstanceInfo", "version", b"version"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... _WhichOneofReturnType__historyPropagationScope: _TypeAlias = _typing.Literal["historyPropagationScope"] # noqa: Y015 _WhichOneofArgType__historyPropagationScope: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope"] # noqa: Y015 _WhichOneofReturnType__rerunParentInstanceInfo: _TypeAlias = _typing.Literal["rerunParentInstanceInfo"] # noqa: Y015 _WhichOneofArgType__rerunParentInstanceInfo: _TypeAlias = _typing.Literal["_rerunParentInstanceInfo", b"_rerunParentInstanceInfo"] # noqa: Y015 + _WhichOneofReturnType__retryParentInstanceInfo: _TypeAlias = _typing.Literal["retryParentInstanceInfo"] # noqa: Y015 + _WhichOneofArgType__retryParentInstanceInfo: _TypeAlias = _typing.Literal["_retryParentInstanceInfo", b"_retryParentInstanceInfo"] # noqa: Y015 @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__historyPropagationScope) -> _WhichOneofReturnType__historyPropagationScope | None: ... @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__rerunParentInstanceInfo) -> _WhichOneofReturnType__rerunParentInstanceInfo | None: ... + @_typing.overload + def WhichOneof(self, oneof_group: _WhichOneofArgType__retryParentInstanceInfo) -> _WhichOneofReturnType__retryParentInstanceInfo | None: ... Global___ChildWorkflowInstanceCreatedEvent: _TypeAlias = ChildWorkflowInstanceCreatedEvent # noqa: Y015 diff --git a/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.py b/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.py index c5719c1a7..45f573eb9 100644 --- a/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.py +++ b/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.py @@ -26,7 +26,7 @@ from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13orchestration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\x83\x01\n\nTaskRouter\x12\x13\n\x0bsourceAppID\x18\x01 \x01(\t\x12\x18\n\x0btargetAppID\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x1f\n\x12targetAppNamespace\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x0e\n\x0c_targetAppIDB\x15\n\x13_targetAppNamespace\">\n\x0fWorkflowVersion\x12\x0f\n\x07patches\x18\x01 \x03(\t\x12\x11\n\x04name\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x07\n\x05_name\"Y\n\x10WorkflowInstance\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x31\n\x0b\x65xecutionId\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\xb2\x01\n\x12TaskFailureDetails\x12\x11\n\terrorType\x18\x01 \x01(\t\x12\x14\n\x0c\x65rrorMessage\x18\x02 \x01(\t\x12\x30\n\nstackTrace\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12)\n\x0cinnerFailure\x18\x04 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x16\n\x0eisNonRetriable\x18\x05 \x01(\x08\"\xff\x01\n\x12ParentInstanceInfo\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12*\n\x04name\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x10workflowInstance\x18\x04 \x01(\x0b\x32\x11.WorkflowInstance\x12\x12\n\x05\x61ppID\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0c\x61ppNamespace\x18\x06 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_appIDB\x0f\n\r_appNamespace\"-\n\x17RerunParentInstanceInfo\x12\x12\n\ninstanceID\x18\x01 \x01(\t\"i\n\x0cTraceContext\x12\x13\n\x0btraceParent\x18\x01 \x01(\t\x12\x12\n\x06spanID\x18\x02 \x01(\tB\x02\x18\x01\x12\x30\n\ntraceState\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\xef\x05\n\rWorkflowState\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12,\n\x0eworkflowStatus\x18\x04 \x01(\x0e\x32\x14.OrchestrationStatus\x12;\n\x17scheduledStartTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x34\n\x10\x63reatedTimestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x38\n\x14lastUpdatedTimestamp\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\x05input\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12,\n\x06output\x18\t \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x32\n\x0c\x63ustomStatus\x18\n \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\x0b \x01(\x0b\x32\x13.TaskFailureDetails\x12\x31\n\x0b\x65xecutionId\x18\x0c \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x36\n\x12\x63ompletedTimestamp\x18\r \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x36\n\x10parentInstanceId\x18\x0e \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12&\n\x04tags\x18\x0f \x03(\x0b\x32\x18.WorkflowState.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01*Y\n\rStalledReason\x12\x12\n\x0ePATCH_MISMATCH\x10\x00\x12\x19\n\x15VERSION_NOT_AVAILABLE\x10\x01\x12\x19\n\x15PAYLOAD_SIZE_EXCEEDED\x10\x02*\xd7\x02\n\x13OrchestrationStatus\x12 \n\x1cORCHESTRATION_STATUS_RUNNING\x10\x00\x12\"\n\x1eORCHESTRATION_STATUS_COMPLETED\x10\x01\x12)\n%ORCHESTRATION_STATUS_CONTINUED_AS_NEW\x10\x02\x12\x1f\n\x1bORCHESTRATION_STATUS_FAILED\x10\x03\x12!\n\x1dORCHESTRATION_STATUS_CANCELED\x10\x04\x12#\n\x1fORCHESTRATION_STATUS_TERMINATED\x10\x05\x12 \n\x1cORCHESTRATION_STATUS_PENDING\x10\x06\x12\"\n\x1eORCHESTRATION_STATUS_SUSPENDED\x10\x07\x12 \n\x1cORCHESTRATION_STATUS_STALLED\x10\x08*\x8f\x01\n\x17HistoryPropagationScope\x12\"\n\x1eHISTORY_PROPAGATION_SCOPE_NONE\x10\x00\x12)\n%HISTORY_PROPAGATION_SCOPE_OWN_HISTORY\x10\x01\x12%\n!HISTORY_PROPAGATION_SCOPE_LINEAGE\x10\x02\x42V\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13orchestration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\x83\x01\n\nTaskRouter\x12\x13\n\x0bsourceAppID\x18\x01 \x01(\t\x12\x18\n\x0btargetAppID\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x1f\n\x12targetAppNamespace\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x0e\n\x0c_targetAppIDB\x15\n\x13_targetAppNamespace\">\n\x0fWorkflowVersion\x12\x0f\n\x07patches\x18\x01 \x03(\t\x12\x11\n\x04name\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x07\n\x05_name\"Y\n\x10WorkflowInstance\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x31\n\x0b\x65xecutionId\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\xb2\x01\n\x12TaskFailureDetails\x12\x11\n\terrorType\x18\x01 \x01(\t\x12\x14\n\x0c\x65rrorMessage\x18\x02 \x01(\t\x12\x30\n\nstackTrace\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12)\n\x0cinnerFailure\x18\x04 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x16\n\x0eisNonRetriable\x18\x05 \x01(\x08\"\xff\x01\n\x12ParentInstanceInfo\x12\x17\n\x0ftaskScheduledId\x18\x01 \x01(\x05\x12*\n\x04name\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x10workflowInstance\x18\x04 \x01(\x0b\x32\x11.WorkflowInstance\x12\x12\n\x05\x61ppID\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0c\x61ppNamespace\x18\x06 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_appIDB\x0f\n\r_appNamespace\"-\n\x17RerunParentInstanceInfo\x12\x12\n\ninstanceID\x18\x01 \x01(\t\"-\n\x17RetryParentInstanceInfo\x12\x12\n\ninstanceID\x18\x01 \x01(\t\"i\n\x0cTraceContext\x12\x13\n\x0btraceParent\x18\x01 \x01(\t\x12\x12\n\x06spanID\x18\x02 \x01(\tB\x02\x18\x01\x12\x30\n\ntraceState\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\xe4\x06\n\rWorkflowState\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12,\n\x0eworkflowStatus\x18\x04 \x01(\x0e\x32\x14.OrchestrationStatus\x12;\n\x17scheduledStartTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x34\n\x10\x63reatedTimestamp\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x38\n\x14lastUpdatedTimestamp\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\x05input\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12,\n\x06output\x18\t \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x32\n\x0c\x63ustomStatus\x18\n \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\x0b \x01(\x0b\x32\x13.TaskFailureDetails\x12\x31\n\x0b\x65xecutionId\x18\x0c \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x36\n\x12\x63ompletedTimestamp\x18\r \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x36\n\x10parentInstanceId\x18\x0e \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12&\n\x04tags\x18\x0f \x03(\x0b\x32\x18.WorkflowState.TagsEntry\x12\x31\n\x0bparentAppId\x18\x10 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x32\n\tstartedAt\x18\x11 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0c\n\n_startedAt*Y\n\rStalledReason\x12\x12\n\x0ePATCH_MISMATCH\x10\x00\x12\x19\n\x15VERSION_NOT_AVAILABLE\x10\x01\x12\x19\n\x15PAYLOAD_SIZE_EXCEEDED\x10\x02*\xd7\x02\n\x13OrchestrationStatus\x12 \n\x1cORCHESTRATION_STATUS_RUNNING\x10\x00\x12\"\n\x1eORCHESTRATION_STATUS_COMPLETED\x10\x01\x12)\n%ORCHESTRATION_STATUS_CONTINUED_AS_NEW\x10\x02\x12\x1f\n\x1bORCHESTRATION_STATUS_FAILED\x10\x03\x12!\n\x1dORCHESTRATION_STATUS_CANCELED\x10\x04\x12#\n\x1fORCHESTRATION_STATUS_TERMINATED\x10\x05\x12 \n\x1cORCHESTRATION_STATUS_PENDING\x10\x06\x12\"\n\x1eORCHESTRATION_STATUS_SUSPENDED\x10\x07\x12 \n\x1cORCHESTRATION_STATUS_STALLED\x10\x08*\x8f\x01\n\x17HistoryPropagationScope\x12\"\n\x1eHISTORY_PROPAGATION_SCOPE_NONE\x10\x00\x12)\n%HISTORY_PROPAGATION_SCOPE_OWN_HISTORY\x10\x01\x12%\n!HISTORY_PROPAGATION_SCOPE_LINEAGE\x10\x02\x42V\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -38,12 +38,12 @@ _globals['_TRACECONTEXT'].fields_by_name['spanID']._serialized_options = b'\030\001' _globals['_WORKFLOWSTATE_TAGSENTRY']._loaded_options = None _globals['_WORKFLOWSTATE_TAGSENTRY']._serialized_options = b'8\001' - _globals['_STALLEDREASON']._serialized_start=1724 - _globals['_STALLEDREASON']._serialized_end=1813 - _globals['_ORCHESTRATIONSTATUS']._serialized_start=1816 - _globals['_ORCHESTRATIONSTATUS']._serialized_end=2159 - _globals['_HISTORYPROPAGATIONSCOPE']._serialized_start=2162 - _globals['_HISTORYPROPAGATIONSCOPE']._serialized_end=2305 + _globals['_STALLEDREASON']._serialized_start=1888 + _globals['_STALLEDREASON']._serialized_end=1977 + _globals['_ORCHESTRATIONSTATUS']._serialized_start=1980 + _globals['_ORCHESTRATIONSTATUS']._serialized_end=2323 + _globals['_HISTORYPROPAGATIONSCOPE']._serialized_start=2326 + _globals['_HISTORYPROPAGATIONSCOPE']._serialized_end=2469 _globals['_TASKROUTER']._serialized_start=89 _globals['_TASKROUTER']._serialized_end=220 _globals['_WORKFLOWVERSION']._serialized_start=222 @@ -56,10 +56,12 @@ _globals['_PARENTINSTANCEINFO']._serialized_end=814 _globals['_RERUNPARENTINSTANCEINFO']._serialized_start=816 _globals['_RERUNPARENTINSTANCEINFO']._serialized_end=861 - _globals['_TRACECONTEXT']._serialized_start=863 - _globals['_TRACECONTEXT']._serialized_end=968 - _globals['_WORKFLOWSTATE']._serialized_start=971 - _globals['_WORKFLOWSTATE']._serialized_end=1722 - _globals['_WORKFLOWSTATE_TAGSENTRY']._serialized_start=1679 - _globals['_WORKFLOWSTATE_TAGSENTRY']._serialized_end=1722 + _globals['_RETRYPARENTINSTANCEINFO']._serialized_start=863 + _globals['_RETRYPARENTINSTANCEINFO']._serialized_end=908 + _globals['_TRACECONTEXT']._serialized_start=910 + _globals['_TRACECONTEXT']._serialized_end=1015 + _globals['_WORKFLOWSTATE']._serialized_start=1018 + _globals['_WORKFLOWSTATE']._serialized_end=1886 + _globals['_WORKFLOWSTATE_TAGSENTRY']._serialized_start=1829 + _globals['_WORKFLOWSTATE_TAGSENTRY']._serialized_end=1872 # @@protoc_insertion_point(module_scope) diff --git a/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.pyi b/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.pyi index 10b22698f..8e2cbb88c 100644 --- a/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.pyi +++ b/dapr/ext/workflow/_durabletask/internal/orchestration_pb2.pyi @@ -294,6 +294,39 @@ class RerunParentInstanceInfo(_message.Message): Global___RerunParentInstanceInfo: _TypeAlias = RerunParentInstanceInfo # noqa: Y015 +@_typing.final +class RetryParentInstanceInfo(_message.Message): + """RetryParentInstanceInfo correlates a child-workflow retry attempt with the + initial attempt that spawned it. When a child workflow is scheduled with a + retry policy, each retry executes as a separate child workflow instance with + its own auto-generated instance ID. This message provides an explicit, + first-class link back to the first attempt so consumers no longer need to + reconstruct the relationship from event ordering and timer origins. + + Semantics: the first attempt carries no RetryParentInstanceInfo. Retry + attempts (2nd onward) carry RetryParentInstanceInfo with instanceID set to + the first attempt's instance ID. Consumers group attempts by reading the + parent workflow's history; the group key is retryParentInstanceInfo.instanceID + when present, otherwise the event's own instanceId. + """ + + DESCRIPTOR: _descriptor.Descriptor + + INSTANCEID_FIELD_NUMBER: _builtins.int + instanceID: _builtins.str + """instanceID is the instance ID of the first attempt in this child-workflow + retry chain. + """ + def __init__( + self, + *, + instanceID: _builtins.str = ..., + ) -> None: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["instanceID", b"instanceID"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + +Global___RetryParentInstanceInfo: _TypeAlias = RetryParentInstanceInfo # noqa: Y015 + @_typing.final class TraceContext(_message.Message): DESCRIPTOR: _descriptor.Descriptor @@ -360,6 +393,8 @@ class WorkflowState(_message.Message): COMPLETEDTIMESTAMP_FIELD_NUMBER: _builtins.int PARENTINSTANCEID_FIELD_NUMBER: _builtins.int TAGS_FIELD_NUMBER: _builtins.int + PARENTAPPID_FIELD_NUMBER: _builtins.int + STARTEDAT_FIELD_NUMBER: _builtins.int instanceId: _builtins.str name: _builtins.str workflowStatus: Global___OrchestrationStatus.ValueType @@ -387,6 +422,10 @@ class WorkflowState(_message.Message): def parentInstanceId(self) -> _wrappers_pb2.StringValue: ... @_builtins.property def tags(self) -> _containers.ScalarMap[_builtins.str, _builtins.str]: ... + @_builtins.property + def parentAppId(self) -> _wrappers_pb2.StringValue: ... + @_builtins.property + def startedAt(self) -> _timestamp_pb2.Timestamp: ... def __init__( self, *, @@ -405,10 +444,15 @@ class WorkflowState(_message.Message): completedTimestamp: _timestamp_pb2.Timestamp | None = ..., parentInstanceId: _wrappers_pb2.StringValue | None = ..., tags: _abc.Mapping[_builtins.str, _builtins.str] | None = ..., + parentAppId: _wrappers_pb2.StringValue | None = ..., + startedAt: _timestamp_pb2.Timestamp | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["completedTimestamp", b"completedTimestamp", "createdTimestamp", b"createdTimestamp", "customStatus", b"customStatus", "executionId", b"executionId", "failureDetails", b"failureDetails", "input", b"input", "lastUpdatedTimestamp", b"lastUpdatedTimestamp", "output", b"output", "parentInstanceId", b"parentInstanceId", "scheduledStartTimestamp", b"scheduledStartTimestamp", "version", b"version"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_startedAt", b"_startedAt", "completedTimestamp", b"completedTimestamp", "createdTimestamp", b"createdTimestamp", "customStatus", b"customStatus", "executionId", b"executionId", "failureDetails", b"failureDetails", "input", b"input", "lastUpdatedTimestamp", b"lastUpdatedTimestamp", "output", b"output", "parentAppId", b"parentAppId", "parentInstanceId", b"parentInstanceId", "scheduledStartTimestamp", b"scheduledStartTimestamp", "startedAt", b"startedAt", "version", b"version"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["completedTimestamp", b"completedTimestamp", "createdTimestamp", b"createdTimestamp", "customStatus", b"customStatus", "executionId", b"executionId", "failureDetails", b"failureDetails", "input", b"input", "instanceId", b"instanceId", "lastUpdatedTimestamp", b"lastUpdatedTimestamp", "name", b"name", "output", b"output", "parentInstanceId", b"parentInstanceId", "scheduledStartTimestamp", b"scheduledStartTimestamp", "tags", b"tags", "version", b"version", "workflowStatus", b"workflowStatus"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_startedAt", b"_startedAt", "completedTimestamp", b"completedTimestamp", "createdTimestamp", b"createdTimestamp", "customStatus", b"customStatus", "executionId", b"executionId", "failureDetails", b"failureDetails", "input", b"input", "instanceId", b"instanceId", "lastUpdatedTimestamp", b"lastUpdatedTimestamp", "name", b"name", "output", b"output", "parentAppId", b"parentAppId", "parentInstanceId", b"parentInstanceId", "scheduledStartTimestamp", b"scheduledStartTimestamp", "startedAt", b"startedAt", "tags", b"tags", "version", b"version", "workflowStatus", b"workflowStatus"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType__startedAt: _TypeAlias = _typing.Literal["startedAt"] # noqa: Y015 + _WhichOneofArgType__startedAt: _TypeAlias = _typing.Literal["_startedAt", b"_startedAt"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType__startedAt) -> _WhichOneofReturnType__startedAt | None: ... Global___WorkflowState: _TypeAlias = WorkflowState # noqa: Y015 diff --git a/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.py b/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.py index 9af283e56..503b5773e 100644 --- a/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.py +++ b/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.py @@ -28,7 +28,7 @@ from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aorchestrator_actions.proto\x1a\x13orchestration.proto\x1a\x14history_events.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xa0\x02\n\x12ScheduleTaskAction\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12 \n\x06router\x18\x04 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x12\x17\n\x0ftaskExecutionId\x18\x05 \x01(\t\x12>\n\x17historyPropagationScope\x18\x06 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x01\x88\x01\x01\x42\t\n\x07_routerB\x1a\n\x18_historyPropagationScope\"\xa2\x02\n\x19\x43reateChildWorkflowAction\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12 \n\x06router\x18\x05 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x12>\n\x17historyPropagationScope\x18\x06 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x01\x88\x01\x01\x42\t\n\x07_routerB\x1a\n\x18_historyPropagationScope\"\x85\x04\n\x1c\x43reateDetachedWorkflowAction\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12@\n\x17scheduledStartTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x31\n\x0b\x65xecutionId\x18\x06 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x35\n\x04tags\x18\x07 \x03(\x0b\x32\'.CreateDetachedWorkflowAction.TagsEntry\x12.\n\x12parentTraceContext\x18\x08 \x01(\x0b\x32\r.TraceContextH\x01\x88\x01\x01\x12 \n\x06router\x18\t \x01(\x0b\x32\x0b.TaskRouterH\x02\x88\x01\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x1a\n\x18_scheduledStartTimestampB\x15\n\x13_parentTraceContextB\t\n\x07_router\"\xbb\x02\n\x11\x43reateTimerAction\x12*\n\x06\x66ireAt\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x11\n\x04name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12.\n\x0b\x63reateTimer\x18\x03 \x01(\x0b\x32\x17.TimerOriginCreateTimerH\x00\x12\x32\n\rexternalEvent\x18\x04 \x01(\x0b\x32\x19.TimerOriginExternalEventH\x00\x12\x32\n\ractivityRetry\x18\x05 \x01(\x0b\x32\x19.TimerOriginActivityRetryH\x00\x12<\n\x12\x63hildWorkflowRetry\x18\x06 \x01(\x0b\x32\x1e.TimerOriginChildWorkflowRetryH\x00\x42\x08\n\x06originB\x07\n\x05_name\"p\n\x0fSendEventAction\x12#\n\x08instance\x18\x01 \x01(\x0b\x32\x11.WorkflowInstance\x12\x0c\n\x04name\x18\x02 \x01(\t\x12*\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\xaa\x02\n\x16\x43ompleteWorkflowAction\x12,\n\x0eworkflowStatus\x18\x01 \x01(\x0e\x32\x14.OrchestrationStatus\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12-\n\x07\x64\x65tails\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x30\n\nnewVersion\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12&\n\x0f\x63\x61rryoverEvents\x18\x05 \x03(\x0b\x32\r.HistoryEvent\x12+\n\x0e\x66\x61ilureDetails\x18\x06 \x01(\x0b\x32\x13.TaskFailureDetails\"l\n\x17TerminateWorkflowAction\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06reason\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x0f\n\x07recurse\x18\x03 \x01(\x08\"#\n!WorkflowVersionNotAvailableAction\"\x97\x04\n\x0eWorkflowAction\x12\n\n\x02id\x18\x01 \x01(\x05\x12+\n\x0cscheduleTask\x18\x02 \x01(\x0b\x32\x13.ScheduleTaskActionH\x00\x12\x39\n\x13\x63reateChildWorkflow\x18\x03 \x01(\x0b\x32\x1a.CreateChildWorkflowActionH\x00\x12)\n\x0b\x63reateTimer\x18\x04 \x01(\x0b\x32\x12.CreateTimerActionH\x00\x12%\n\tsendEvent\x18\x05 \x01(\x0b\x32\x10.SendEventActionH\x00\x12\x33\n\x10\x63ompleteWorkflow\x18\x06 \x01(\x0b\x32\x17.CompleteWorkflowActionH\x00\x12\x35\n\x11terminateWorkflow\x18\x07 \x01(\x0b\x32\x18.TerminateWorkflowActionH\x00\x12I\n\x1bworkflowVersionNotAvailable\x18\n \x01(\x0b\x32\".WorkflowVersionNotAvailableActionH\x00\x12?\n\x16\x63reateDetachedWorkflow\x18\x0b \x01(\x0b\x32\x1d.CreateDetachedWorkflowActionH\x00\x12 \n\x06router\x18\t \x01(\x0b\x32\x0b.TaskRouterH\x01\x88\x01\x01\x42\x14\n\x12workflowActionTypeB\t\n\x07_routerJ\x04\x08\x08\x10\tBV\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aorchestrator_actions.proto\x1a\x13orchestration.proto\x1a\x14history_events.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\"\xf9\x01\n\x12ScheduleTaskAction\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x17\n\x0ftaskExecutionId\x18\x05 \x01(\t\x12>\n\x17historyPropagationScope\x18\x06 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x00\x88\x01\x01\x42\x1a\n\x18_historyPropagationScopeJ\x04\x08\x04\x10\x05\"\xd7\x02\n\x19\x43reateChildWorkflowAction\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12>\n\x17historyPropagationScope\x18\x06 \x01(\x0e\x32\x18.HistoryPropagationScopeH\x00\x88\x01\x01\x12>\n\x17retryParentInstanceInfo\x18\x07 \x01(\x0b\x32\x18.RetryParentInstanceInfoH\x01\x88\x01\x01\x42\x1a\n\x18_historyPropagationScopeB\x1a\n\x18_retryParentInstanceInfoJ\x04\x08\x05\x10\x06\"\xde\x03\n\x1c\x43reateDetachedWorkflowAction\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12@\n\x17scheduledStartTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x88\x01\x01\x12\x31\n\x0b\x65xecutionId\x18\x06 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x35\n\x04tags\x18\x07 \x03(\x0b\x32\'.CreateDetachedWorkflowAction.TagsEntry\x12.\n\x12parentTraceContext\x18\x08 \x01(\x0b\x32\r.TraceContextH\x01\x88\x01\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x1a\n\x18_scheduledStartTimestampB\x15\n\x13_parentTraceContextJ\x04\x08\t\x10\n\"\xbb\x02\n\x11\x43reateTimerAction\x12*\n\x06\x66ireAt\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x11\n\x04name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12.\n\x0b\x63reateTimer\x18\x03 \x01(\x0b\x32\x17.TimerOriginCreateTimerH\x00\x12\x32\n\rexternalEvent\x18\x04 \x01(\x0b\x32\x19.TimerOriginExternalEventH\x00\x12\x32\n\ractivityRetry\x18\x05 \x01(\x0b\x32\x19.TimerOriginActivityRetryH\x00\x12<\n\x12\x63hildWorkflowRetry\x18\x06 \x01(\x0b\x32\x1e.TimerOriginChildWorkflowRetryH\x00\x42\x08\n\x06originB\x07\n\x05_name\"p\n\x0fSendEventAction\x12#\n\x08instance\x18\x01 \x01(\x0b\x32\x11.WorkflowInstance\x12\x0c\n\x04name\x18\x02 \x01(\t\x12*\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\xaa\x02\n\x16\x43ompleteWorkflowAction\x12,\n\x0eworkflowStatus\x18\x01 \x01(\x0e\x32\x14.OrchestrationStatus\x12,\n\x06result\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12-\n\x07\x64\x65tails\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x30\n\nnewVersion\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12&\n\x0f\x63\x61rryoverEvents\x18\x05 \x03(\x0b\x32\r.HistoryEvent\x12+\n\x0e\x66\x61ilureDetails\x18\x06 \x01(\x0b\x32\x13.TaskFailureDetails\"l\n\x17TerminateWorkflowAction\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06reason\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x0f\n\x07recurse\x18\x03 \x01(\x08\"#\n!WorkflowVersionNotAvailableAction\"\x97\x04\n\x0eWorkflowAction\x12\n\n\x02id\x18\x01 \x01(\x05\x12+\n\x0cscheduleTask\x18\x02 \x01(\x0b\x32\x13.ScheduleTaskActionH\x00\x12\x39\n\x13\x63reateChildWorkflow\x18\x03 \x01(\x0b\x32\x1a.CreateChildWorkflowActionH\x00\x12)\n\x0b\x63reateTimer\x18\x04 \x01(\x0b\x32\x12.CreateTimerActionH\x00\x12%\n\tsendEvent\x18\x05 \x01(\x0b\x32\x10.SendEventActionH\x00\x12\x33\n\x10\x63ompleteWorkflow\x18\x06 \x01(\x0b\x32\x17.CompleteWorkflowActionH\x00\x12\x35\n\x11terminateWorkflow\x18\x07 \x01(\x0b\x32\x18.TerminateWorkflowActionH\x00\x12I\n\x1bworkflowVersionNotAvailable\x18\n \x01(\x0b\x32\".WorkflowVersionNotAvailableActionH\x00\x12?\n\x16\x63reateDetachedWorkflow\x18\x0b \x01(\x0b\x32\x1d.CreateDetachedWorkflowActionH\x00\x12 \n\x06router\x18\t \x01(\x0b\x32\x0b.TaskRouterH\x01\x88\x01\x01\x42\x14\n\x12workflowActionTypeB\t\n\x07_routerJ\x04\x08\x08\x10\tBV\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -39,23 +39,23 @@ _globals['_CREATEDETACHEDWORKFLOWACTION_TAGSENTRY']._loaded_options = None _globals['_CREATEDETACHEDWORKFLOWACTION_TAGSENTRY']._serialized_options = b'8\001' _globals['_SCHEDULETASKACTION']._serialized_start=139 - _globals['_SCHEDULETASKACTION']._serialized_end=427 - _globals['_CREATECHILDWORKFLOWACTION']._serialized_start=430 - _globals['_CREATECHILDWORKFLOWACTION']._serialized_end=720 - _globals['_CREATEDETACHEDWORKFLOWACTION']._serialized_start=723 - _globals['_CREATEDETACHEDWORKFLOWACTION']._serialized_end=1240 - _globals['_CREATEDETACHEDWORKFLOWACTION_TAGSENTRY']._serialized_start=1135 - _globals['_CREATEDETACHEDWORKFLOWACTION_TAGSENTRY']._serialized_end=1178 - _globals['_CREATETIMERACTION']._serialized_start=1243 - _globals['_CREATETIMERACTION']._serialized_end=1558 - _globals['_SENDEVENTACTION']._serialized_start=1560 - _globals['_SENDEVENTACTION']._serialized_end=1672 - _globals['_COMPLETEWORKFLOWACTION']._serialized_start=1675 - _globals['_COMPLETEWORKFLOWACTION']._serialized_end=1973 - _globals['_TERMINATEWORKFLOWACTION']._serialized_start=1975 - _globals['_TERMINATEWORKFLOWACTION']._serialized_end=2083 - _globals['_WORKFLOWVERSIONNOTAVAILABLEACTION']._serialized_start=2085 - _globals['_WORKFLOWVERSIONNOTAVAILABLEACTION']._serialized_end=2120 - _globals['_WORKFLOWACTION']._serialized_start=2123 - _globals['_WORKFLOWACTION']._serialized_end=2658 + _globals['_SCHEDULETASKACTION']._serialized_end=388 + _globals['_CREATECHILDWORKFLOWACTION']._serialized_start=391 + _globals['_CREATECHILDWORKFLOWACTION']._serialized_end=734 + _globals['_CREATEDETACHEDWORKFLOWACTION']._serialized_start=737 + _globals['_CREATEDETACHEDWORKFLOWACTION']._serialized_end=1215 + _globals['_CREATEDETACHEDWORKFLOWACTION_TAGSENTRY']._serialized_start=1115 + _globals['_CREATEDETACHEDWORKFLOWACTION_TAGSENTRY']._serialized_end=1158 + _globals['_CREATETIMERACTION']._serialized_start=1218 + _globals['_CREATETIMERACTION']._serialized_end=1533 + _globals['_SENDEVENTACTION']._serialized_start=1535 + _globals['_SENDEVENTACTION']._serialized_end=1647 + _globals['_COMPLETEWORKFLOWACTION']._serialized_start=1650 + _globals['_COMPLETEWORKFLOWACTION']._serialized_end=1948 + _globals['_TERMINATEWORKFLOWACTION']._serialized_start=1950 + _globals['_TERMINATEWORKFLOWACTION']._serialized_end=2058 + _globals['_WORKFLOWVERSIONNOTAVAILABLEACTION']._serialized_start=2060 + _globals['_WORKFLOWVERSIONNOTAVAILABLEACTION']._serialized_end=2095 + _globals['_WORKFLOWACTION']._serialized_start=2098 + _globals['_WORKFLOWACTION']._serialized_end=2633 # @@protoc_insertion_point(module_scope) diff --git a/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.pyi b/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.pyi index 1934c960f..9e4e3deb0 100644 --- a/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.pyi +++ b/dapr/ext/workflow/_durabletask/internal/orchestrator_actions_pb2.pyi @@ -31,7 +31,6 @@ class ScheduleTaskAction(_message.Message): NAME_FIELD_NUMBER: _builtins.int VERSION_FIELD_NUMBER: _builtins.int INPUT_FIELD_NUMBER: _builtins.int - ROUTER_FIELD_NUMBER: _builtins.int TASKEXECUTIONID_FIELD_NUMBER: _builtins.int HISTORYPROPAGATIONSCOPE_FIELD_NUMBER: _builtins.int name: _builtins.str @@ -42,30 +41,22 @@ class ScheduleTaskAction(_message.Message): def version(self) -> _wrappers_pb2.StringValue: ... @_builtins.property def input(self) -> _wrappers_pb2.StringValue: ... - @_builtins.property - def router(self) -> _orchestration_pb2.TaskRouter: ... def __init__( self, *, name: _builtins.str = ..., version: _wrappers_pb2.StringValue | None = ..., input: _wrappers_pb2.StringValue | None = ..., - router: _orchestration_pb2.TaskRouter | None = ..., taskExecutionId: _builtins.str = ..., historyPropagationScope: _orchestration_pb2.HistoryPropagationScope.ValueType | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_router", b"_router", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "router", b"router", "version", b"version"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "version", b"version"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_router", b"_router", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "name", b"name", "router", b"router", "taskExecutionId", b"taskExecutionId", "version", b"version"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "name", b"name", "taskExecutionId", b"taskExecutionId", "version", b"version"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... _WhichOneofReturnType__historyPropagationScope: _TypeAlias = _typing.Literal["historyPropagationScope"] # noqa: Y015 _WhichOneofArgType__historyPropagationScope: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope"] # noqa: Y015 - _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 - _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 - @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__historyPropagationScope) -> _WhichOneofReturnType__historyPropagationScope | None: ... - @_typing.overload - def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___ScheduleTaskAction: _TypeAlias = ScheduleTaskAction # noqa: Y015 @@ -77,8 +68,8 @@ class CreateChildWorkflowAction(_message.Message): NAME_FIELD_NUMBER: _builtins.int VERSION_FIELD_NUMBER: _builtins.int INPUT_FIELD_NUMBER: _builtins.int - ROUTER_FIELD_NUMBER: _builtins.int HISTORYPROPAGATIONSCOPE_FIELD_NUMBER: _builtins.int + RETRYPARENTINSTANCEINFO_FIELD_NUMBER: _builtins.int instanceId: _builtins.str name: _builtins.str historyPropagationScope: _orchestration_pb2.HistoryPropagationScope.ValueType @@ -88,7 +79,15 @@ class CreateChildWorkflowAction(_message.Message): @_builtins.property def input(self) -> _wrappers_pb2.StringValue: ... @_builtins.property - def router(self) -> _orchestration_pb2.TaskRouter: ... + def retryParentInstanceInfo(self) -> _orchestration_pb2.RetryParentInstanceInfo: + """If defined, indicates that this child workflow is a retry attempt and + links it back to the first attempt in the retry chain. Absent on the + first attempt. The runtime persists this onto the resulting + ChildWorkflowInstanceCreatedEvent so consumers can correlate retry + attempts by grouping on retryParentInstanceInfo.instanceID when present, + otherwise on the created instance's own instanceId. + """ + def __init__( self, *, @@ -96,21 +95,21 @@ class CreateChildWorkflowAction(_message.Message): name: _builtins.str = ..., version: _wrappers_pb2.StringValue | None = ..., input: _wrappers_pb2.StringValue | None = ..., - router: _orchestration_pb2.TaskRouter | None = ..., historyPropagationScope: _orchestration_pb2.HistoryPropagationScope.ValueType | None = ..., + retryParentInstanceInfo: _orchestration_pb2.RetryParentInstanceInfo | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_router", b"_router", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "router", b"router", "version", b"version"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_retryParentInstanceInfo", b"_retryParentInstanceInfo", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "retryParentInstanceInfo", b"retryParentInstanceInfo", "version", b"version"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_router", b"_router", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "instanceId", b"instanceId", "name", b"name", "router", b"router", "version", b"version"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope", "_retryParentInstanceInfo", b"_retryParentInstanceInfo", "historyPropagationScope", b"historyPropagationScope", "input", b"input", "instanceId", b"instanceId", "name", b"name", "retryParentInstanceInfo", b"retryParentInstanceInfo", "version", b"version"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... _WhichOneofReturnType__historyPropagationScope: _TypeAlias = _typing.Literal["historyPropagationScope"] # noqa: Y015 _WhichOneofArgType__historyPropagationScope: _TypeAlias = _typing.Literal["_historyPropagationScope", b"_historyPropagationScope"] # noqa: Y015 - _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 - _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 + _WhichOneofReturnType__retryParentInstanceInfo: _TypeAlias = _typing.Literal["retryParentInstanceInfo"] # noqa: Y015 + _WhichOneofArgType__retryParentInstanceInfo: _TypeAlias = _typing.Literal["_retryParentInstanceInfo", b"_retryParentInstanceInfo"] # noqa: Y015 @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__historyPropagationScope) -> _WhichOneofReturnType__historyPropagationScope | None: ... @_typing.overload - def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... + def WhichOneof(self, oneof_group: _WhichOneofArgType__retryParentInstanceInfo) -> _WhichOneofReturnType__retryParentInstanceInfo | None: ... Global___CreateChildWorkflowAction: _TypeAlias = CreateChildWorkflowAction # noqa: Y015 @@ -153,7 +152,6 @@ class CreateDetachedWorkflowAction(_message.Message): EXECUTIONID_FIELD_NUMBER: _builtins.int TAGS_FIELD_NUMBER: _builtins.int PARENTTRACECONTEXT_FIELD_NUMBER: _builtins.int - ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str """instanceId is the ID assigned to the new workflow. It is mandatory: implementors must set a stable, deterministic ID so that on replay the @@ -179,8 +177,6 @@ class CreateDetachedWorkflowAction(_message.Message): def tags(self) -> _containers.ScalarMap[_builtins.str, _builtins.str]: ... @_builtins.property def parentTraceContext(self) -> _orchestration_pb2.TraceContext: ... - @_builtins.property - def router(self) -> _orchestration_pb2.TaskRouter: ... def __init__( self, *, @@ -192,23 +188,18 @@ class CreateDetachedWorkflowAction(_message.Message): executionId: _wrappers_pb2.StringValue | None = ..., tags: _abc.Mapping[_builtins.str, _builtins.str] | None = ..., parentTraceContext: _orchestration_pb2.TraceContext | None = ..., - router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["_parentTraceContext", b"_parentTraceContext", "_router", b"_router", "_scheduledStartTimestamp", b"_scheduledStartTimestamp", "executionId", b"executionId", "input", b"input", "parentTraceContext", b"parentTraceContext", "router", b"router", "scheduledStartTimestamp", b"scheduledStartTimestamp", "version", b"version"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_parentTraceContext", b"_parentTraceContext", "_scheduledStartTimestamp", b"_scheduledStartTimestamp", "executionId", b"executionId", "input", b"input", "parentTraceContext", b"parentTraceContext", "scheduledStartTimestamp", b"scheduledStartTimestamp", "version", b"version"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["_parentTraceContext", b"_parentTraceContext", "_router", b"_router", "_scheduledStartTimestamp", b"_scheduledStartTimestamp", "executionId", b"executionId", "input", b"input", "instanceId", b"instanceId", "name", b"name", "parentTraceContext", b"parentTraceContext", "router", b"router", "scheduledStartTimestamp", b"scheduledStartTimestamp", "tags", b"tags", "version", b"version"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_parentTraceContext", b"_parentTraceContext", "_scheduledStartTimestamp", b"_scheduledStartTimestamp", "executionId", b"executionId", "input", b"input", "instanceId", b"instanceId", "name", b"name", "parentTraceContext", b"parentTraceContext", "scheduledStartTimestamp", b"scheduledStartTimestamp", "tags", b"tags", "version", b"version"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... _WhichOneofReturnType__parentTraceContext: _TypeAlias = _typing.Literal["parentTraceContext"] # noqa: Y015 _WhichOneofArgType__parentTraceContext: _TypeAlias = _typing.Literal["_parentTraceContext", b"_parentTraceContext"] # noqa: Y015 - _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 - _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 _WhichOneofReturnType__scheduledStartTimestamp: _TypeAlias = _typing.Literal["scheduledStartTimestamp"] # noqa: Y015 _WhichOneofArgType__scheduledStartTimestamp: _TypeAlias = _typing.Literal["_scheduledStartTimestamp", b"_scheduledStartTimestamp"] # noqa: Y015 @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__parentTraceContext) -> _WhichOneofReturnType__parentTraceContext | None: ... @_typing.overload - def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... - @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__scheduledStartTimestamp) -> _WhichOneofReturnType__scheduledStartTimestamp | None: ... Global___CreateDetachedWorkflowAction: _TypeAlias = CreateDetachedWorkflowAction # noqa: Y015 diff --git a/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.py b/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.py index 443535186..80f69c149 100644 --- a/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.py +++ b/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.py @@ -30,7 +30,7 @@ from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aorchestrator_service.proto\x1a\x13orchestration.proto\x1a\x14history_events.proto\x1a\x1aorchestrator_actions.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1bgoogle/protobuf/empty.proto\"\xc6\x02\n\x0f\x41\x63tivityRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x10workflowInstance\x18\x04 \x01(\x0b\x32\x11.WorkflowInstance\x12\x0e\n\x06taskId\x18\x05 \x01(\x05\x12)\n\x12parentTraceContext\x18\x06 \x01(\x0b\x32\r.TraceContext\x12\x17\n\x0ftaskExecutionId\x18\x07 \x01(\t\x12\x32\n\x11propagatedHistory\x18\x08 \x01(\x0b\x32\x12.PropagatedHistoryH\x00\x88\x01\x01\x42\x14\n\x12_propagatedHistory\"\xaa\x01\n\x10\x41\x63tivityResponse\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0e\n\x06taskId\x18\x02 \x01(\x05\x12,\n\x06result\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\x04 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x17\n\x0f\x63ompletionToken\x18\x05 \x01(\t\"#\n\rCachedHistory\x12\x12\n\neventCount\x18\x01 \x01(\x05\"\xfa\x02\n\x0fWorkflowRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x31\n\x0b\x65xecutionId\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12!\n\npastEvents\x18\x03 \x03(\x0b\x32\r.HistoryEvent\x12 \n\tnewEvents\x18\x04 \x03(\x0b\x32\r.HistoryEvent\x12 \n\x18requiresHistoryStreaming\x18\x06 \x01(\x08\x12 \n\x06router\x18\x07 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x12\x32\n\x11propagatedHistory\x18\x08 \x01(\x0b\x32\x12.PropagatedHistoryH\x01\x88\x01\x01\x12*\n\rcachedHistory\x18\t \x01(\x0b\x32\x0e.CachedHistoryH\x02\x88\x01\x01\x42\t\n\x07_routerB\x14\n\x12_propagatedHistoryB\x10\n\x0e_cachedHistoryJ\x04\x08\x05\x10\x06\"\x82\x02\n\x10WorkflowResponse\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12 \n\x07\x61\x63tions\x18\x02 \x03(\x0b\x32\x0f.WorkflowAction\x12\x32\n\x0c\x63ustomStatus\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x17\n\x0f\x63ompletionToken\x18\x04 \x01(\t\x12\x37\n\x12numEventsProcessed\x18\x05 \x01(\x0b\x32\x1b.google.protobuf.Int32Value\x12&\n\x07version\x18\x06 \x01(\x0b\x32\x10.WorkflowVersionH\x00\x88\x01\x01\x42\n\n\x08_version\"\xaf\x03\n\x15\x43reateInstanceRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12;\n\x17scheduledStartTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x31\n\x0b\x65xecutionId\x18\x07 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12.\n\x04tags\x18\x08 \x03(\x0b\x32 .CreateInstanceRequest.TagsEntry\x12)\n\x12parentTraceContext\x18\t \x01(\x0b\x32\r.TraceContext\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01J\x04\x08\x06\x10\x07R\x1aorchestrationIdReusePolicy\",\n\x16\x43reateInstanceResponse\x12\x12\n\ninstanceId\x18\x01 \x01(\t\"E\n\x12GetInstanceRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x1b\n\x13getInputsAndOutputs\x18\x02 \x01(\x08\"L\n\x13GetInstanceResponse\x12\x0e\n\x06\x65xists\x18\x01 \x01(\x08\x12%\n\rworkflowState\x18\x02 \x01(\x0b\x32\x0e.WorkflowState\"b\n\x11RaiseEventRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\x14\n\x12RaiseEventResponse\"g\n\x10TerminateRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06output\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x11\n\trecursive\x18\x03 \x01(\x08\"\x13\n\x11TerminateResponse\"R\n\x0eSuspendRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06reason\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\x11\n\x0fSuspendResponse\"Q\n\rResumeRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06reason\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\"\x10\n\x0eResumeResponse\"\x9e\x01\n\x15PurgeInstancesRequest\x12\x14\n\ninstanceId\x18\x01 \x01(\tH\x00\x12\x33\n\x13purgeInstanceFilter\x18\x02 \x01(\x0b\x32\x14.PurgeInstanceFilterH\x00\x12\x11\n\trecursive\x18\x03 \x01(\x08\x12\x12\n\x05\x66orce\x18\x04 \x01(\x08H\x01\x88\x01\x01\x42\t\n\x07requestB\x08\n\x06_force\"\xaa\x01\n\x13PurgeInstanceFilter\x12\x33\n\x0f\x63reatedTimeFrom\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x31\n\rcreatedTimeTo\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\rruntimeStatus\x18\x03 \x03(\x0e\x32\x14.OrchestrationStatus\"f\n\x16PurgeInstancesResponse\x12\x1c\n\x14\x64\x65letedInstanceCount\x18\x01 \x01(\x05\x12.\n\nisComplete\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\"V\n\x13GetWorkItemsRequest\x12\'\n\x0c\x63\x61pabilities\x18\x04 \x03(\x0e\x32\x11.WorkerCapabilityJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04J\x04\x08\n\x10\x0b\"\x9a\x01\n\x08WorkItem\x12+\n\x0fworkflowRequest\x18\x01 \x01(\x0b\x32\x10.WorkflowRequestH\x00\x12+\n\x0f\x61\x63tivityRequest\x18\x02 \x01(\x0b\x32\x10.ActivityRequestH\x00\x12\x17\n\x0f\x63ompletionToken\x18\n \x01(\tB\t\n\x07requestJ\x04\x08\x03\x10\x04J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06\"\x16\n\x14\x43ompleteTaskResponse\"\x85\x02\n\x1dRerunWorkflowFromEventRequest\x12\x18\n\x10sourceInstanceID\x18\x01 \x01(\t\x12\x0f\n\x07\x65ventID\x18\x02 \x01(\r\x12\x1a\n\rnewInstanceID\x18\x03 \x01(\tH\x00\x88\x01\x01\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x16\n\x0eoverwriteInput\x18\x05 \x01(\x08\x12\'\n\x1anewChildWorkflowInstanceID\x18\x06 \x01(\tH\x01\x88\x01\x01\x42\x10\n\x0e_newInstanceIDB\x1d\n\x1b_newChildWorkflowInstanceID\"7\n\x1eRerunWorkflowFromEventResponse\x12\x15\n\rnewInstanceID\x18\x01 \x01(\t\"r\n\x16ListInstanceIDsRequest\x12\x1e\n\x11\x63ontinuationToken\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x15\n\x08pageSize\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x14\n\x12_continuationTokenB\x0b\n\t_pageSize\"d\n\x17ListInstanceIDsResponse\x12\x13\n\x0binstanceIds\x18\x01 \x03(\t\x12\x1e\n\x11\x63ontinuationToken\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x14\n\x12_continuationToken\"/\n\x19GetInstanceHistoryRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\";\n\x1aGetInstanceHistoryResponse\x12\x1d\n\x06\x65vents\x18\x01 \x03(\x0b\x32\r.HistoryEvent*\x88\x01\n\x10WorkerCapability\x12!\n\x1dWORKER_CAPABILITY_UNSPECIFIED\x10\x00\x12&\n\"WORKER_CAPABILITY_STATEFUL_HISTORY\x10\x02\"\x04\x08\x01\x10\x01*#WORKER_CAPABILITY_HISTORY_STREAMING2\xe8\x08\n\x15TaskHubSidecarService\x12\x37\n\x05Hello\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12@\n\rStartInstance\x12\x16.CreateInstanceRequest\x1a\x17.CreateInstanceResponse\x12\x38\n\x0bGetInstance\x12\x13.GetInstanceRequest\x1a\x14.GetInstanceResponse\x12\x41\n\x14WaitForInstanceStart\x12\x13.GetInstanceRequest\x1a\x14.GetInstanceResponse\x12\x46\n\x19WaitForInstanceCompletion\x12\x13.GetInstanceRequest\x1a\x14.GetInstanceResponse\x12\x35\n\nRaiseEvent\x12\x12.RaiseEventRequest\x1a\x13.RaiseEventResponse\x12:\n\x11TerminateInstance\x12\x11.TerminateRequest\x1a\x12.TerminateResponse\x12\x34\n\x0fSuspendInstance\x12\x0f.SuspendRequest\x1a\x10.SuspendResponse\x12\x31\n\x0eResumeInstance\x12\x0e.ResumeRequest\x1a\x0f.ResumeResponse\x12\x41\n\x0ePurgeInstances\x12\x16.PurgeInstancesRequest\x1a\x17.PurgeInstancesResponse\x12\x31\n\x0cGetWorkItems\x12\x14.GetWorkItemsRequest\x1a\t.WorkItem0\x01\x12@\n\x14\x43ompleteActivityTask\x12\x11.ActivityResponse\x1a\x15.CompleteTaskResponse\x12I\n\x18\x43ompleteOrchestratorTask\x12\x11.WorkflowResponse\x1a\x15.CompleteTaskResponse\"\x03\x88\x02\x01\x12@\n\x14\x43ompleteWorkflowTask\x12\x11.WorkflowResponse\x1a\x15.CompleteTaskResponse\x12Y\n\x16RerunWorkflowFromEvent\x12\x1e.RerunWorkflowFromEventRequest\x1a\x1f.RerunWorkflowFromEventResponse\x12\x44\n\x0fListInstanceIDs\x12\x17.ListInstanceIDsRequest\x1a\x18.ListInstanceIDsResponse\x12M\n\x12GetInstanceHistory\x12\x1a.GetInstanceHistoryRequest\x1a\x1b.GetInstanceHistoryResponseBV\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1aorchestrator_service.proto\x1a\x13orchestration.proto\x1a\x14history_events.proto\x1a\x1aorchestrator_actions.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1bgoogle/protobuf/empty.proto\"\xc6\x02\n\x0f\x41\x63tivityRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\x07version\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x10workflowInstance\x18\x04 \x01(\x0b\x32\x11.WorkflowInstance\x12\x0e\n\x06taskId\x18\x05 \x01(\x05\x12)\n\x12parentTraceContext\x18\x06 \x01(\x0b\x32\r.TraceContext\x12\x17\n\x0ftaskExecutionId\x18\x07 \x01(\t\x12\x32\n\x11propagatedHistory\x18\x08 \x01(\x0b\x32\x12.PropagatedHistoryH\x00\x88\x01\x01\x42\x14\n\x12_propagatedHistory\"\xaa\x01\n\x10\x41\x63tivityResponse\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0e\n\x06taskId\x18\x02 \x01(\x05\x12,\n\x06result\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x0e\x66\x61ilureDetails\x18\x04 \x01(\x0b\x32\x13.TaskFailureDetails\x12\x17\n\x0f\x63ompletionToken\x18\x05 \x01(\t\"#\n\rCachedHistory\x12\x12\n\neventCount\x18\x01 \x01(\x05\"\xfa\x02\n\x0fWorkflowRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x31\n\x0b\x65xecutionId\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12!\n\npastEvents\x18\x03 \x03(\x0b\x32\r.HistoryEvent\x12 \n\tnewEvents\x18\x04 \x03(\x0b\x32\r.HistoryEvent\x12 \n\x18requiresHistoryStreaming\x18\x06 \x01(\x08\x12 \n\x06router\x18\x07 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x12\x32\n\x11propagatedHistory\x18\x08 \x01(\x0b\x32\x12.PropagatedHistoryH\x01\x88\x01\x01\x12*\n\rcachedHistory\x18\t \x01(\x0b\x32\x0e.CachedHistoryH\x02\x88\x01\x01\x42\t\n\x07_routerB\x14\n\x12_propagatedHistoryB\x10\n\x0e_cachedHistoryJ\x04\x08\x05\x10\x06\"\x82\x02\n\x10WorkflowResponse\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12 \n\x07\x61\x63tions\x18\x02 \x03(\x0b\x32\x0f.WorkflowAction\x12\x32\n\x0c\x63ustomStatus\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x17\n\x0f\x63ompletionToken\x18\x04 \x01(\t\x12\x37\n\x12numEventsProcessed\x18\x05 \x01(\x0b\x32\x1b.google.protobuf.Int32Value\x12&\n\x07version\x18\x06 \x01(\x0b\x32\x10.WorkflowVersionH\x00\x88\x01\x01\x42\n\n\x08_version\"\xfd\x03\n\x15\x43reateInstanceRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12-\n\x07version\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12;\n\x17scheduledStartTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x31\n\x0b\x65xecutionId\x18\x07 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12.\n\x04tags\x18\x08 \x03(\x0b\x32 .CreateInstanceRequest.TagsEntry\x12)\n\x12parentTraceContext\x18\t \x01(\x0b\x32\r.TraceContext\x12\x1f\n\x17\x65nforceUniqueInstanceId\x18\n \x01(\x08\x12 \n\x06router\x18\x0b \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_routerJ\x04\x08\x06\x10\x07R\x1aorchestrationIdReusePolicy\",\n\x16\x43reateInstanceResponse\x12\x12\n\ninstanceId\x18\x01 \x01(\t\"r\n\x12GetInstanceRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x1b\n\x13getInputsAndOutputs\x18\x02 \x01(\x08\x12 \n\x06router\x18\x03 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x42\t\n\x07_router\"L\n\x13GetInstanceResponse\x12\x0e\n\x06\x65xists\x18\x01 \x01(\x08\x12%\n\rworkflowState\x18\x02 \x01(\x0b\x32\x0e.WorkflowState\"\x8f\x01\n\x11RaiseEventRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12+\n\x05input\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12 \n\x06router\x18\x04 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x42\t\n\x07_router\"\x14\n\x12RaiseEventResponse\"\x94\x01\n\x10TerminateRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06output\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x11\n\trecursive\x18\x03 \x01(\x08\x12 \n\x06router\x18\x04 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x42\t\n\x07_router\"\x13\n\x11TerminateResponse\"\x7f\n\x0eSuspendRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06reason\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12 \n\x06router\x18\x03 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x42\t\n\x07_router\"\x11\n\x0fSuspendResponse\"~\n\rResumeRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\x12,\n\x06reason\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12 \n\x06router\x18\x03 \x01(\x0b\x32\x0b.TaskRouterH\x00\x88\x01\x01\x42\t\n\x07_router\"\x10\n\x0eResumeResponse\"\xcb\x01\n\x15PurgeInstancesRequest\x12\x14\n\ninstanceId\x18\x01 \x01(\tH\x00\x12\x33\n\x13purgeInstanceFilter\x18\x02 \x01(\x0b\x32\x14.PurgeInstanceFilterH\x00\x12\x11\n\trecursive\x18\x03 \x01(\x08\x12\x12\n\x05\x66orce\x18\x04 \x01(\x08H\x01\x88\x01\x01\x12 \n\x06router\x18\x05 \x01(\x0b\x32\x0b.TaskRouterH\x02\x88\x01\x01\x42\t\n\x07requestB\x08\n\x06_forceB\t\n\x07_router\"\xaa\x01\n\x13PurgeInstanceFilter\x12\x33\n\x0f\x63reatedTimeFrom\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x31\n\rcreatedTimeTo\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12+\n\rruntimeStatus\x18\x03 \x03(\x0e\x32\x14.OrchestrationStatus\"f\n\x16PurgeInstancesResponse\x12\x1c\n\x14\x64\x65letedInstanceCount\x18\x01 \x01(\x05\x12.\n\nisComplete\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\"V\n\x13GetWorkItemsRequest\x12\'\n\x0c\x63\x61pabilities\x18\x04 \x03(\x0e\x32\x11.WorkerCapabilityJ\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04J\x04\x08\n\x10\x0b\"\x9a\x01\n\x08WorkItem\x12+\n\x0fworkflowRequest\x18\x01 \x01(\x0b\x32\x10.WorkflowRequestH\x00\x12+\n\x0f\x61\x63tivityRequest\x18\x02 \x01(\x0b\x32\x10.ActivityRequestH\x00\x12\x17\n\x0f\x63ompletionToken\x18\n \x01(\tB\t\n\x07requestJ\x04\x08\x03\x10\x04J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06\"\x16\n\x14\x43ompleteTaskResponse\"\xb2\x02\n\x1dRerunWorkflowFromEventRequest\x12\x18\n\x10sourceInstanceID\x18\x01 \x01(\t\x12\x0f\n\x07\x65ventID\x18\x02 \x01(\r\x12\x1a\n\rnewInstanceID\x18\x03 \x01(\tH\x00\x88\x01\x01\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x16\n\x0eoverwriteInput\x18\x05 \x01(\x08\x12\'\n\x1anewChildWorkflowInstanceID\x18\x06 \x01(\tH\x01\x88\x01\x01\x12 \n\x06router\x18\x07 \x01(\x0b\x32\x0b.TaskRouterH\x02\x88\x01\x01\x42\x10\n\x0e_newInstanceIDB\x1d\n\x1b_newChildWorkflowInstanceIDB\t\n\x07_router\"7\n\x1eRerunWorkflowFromEventResponse\x12\x15\n\rnewInstanceID\x18\x01 \x01(\t\"r\n\x16ListInstanceIDsRequest\x12\x1e\n\x11\x63ontinuationToken\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x15\n\x08pageSize\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x14\n\x12_continuationTokenB\x0b\n\t_pageSize\"d\n\x17ListInstanceIDsResponse\x12\x13\n\x0binstanceIds\x18\x01 \x03(\t\x12\x1e\n\x11\x63ontinuationToken\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x14\n\x12_continuationToken\"/\n\x19GetInstanceHistoryRequest\x12\x12\n\ninstanceId\x18\x01 \x01(\t\";\n\x1aGetInstanceHistoryResponse\x12\x1d\n\x06\x65vents\x18\x01 \x03(\x0b\x32\r.HistoryEvent*\x88\x01\n\x10WorkerCapability\x12!\n\x1dWORKER_CAPABILITY_UNSPECIFIED\x10\x00\x12&\n\"WORKER_CAPABILITY_STATEFUL_HISTORY\x10\x02\"\x04\x08\x01\x10\x01*#WORKER_CAPABILITY_HISTORY_STREAMING2\xe8\x08\n\x15TaskHubSidecarService\x12\x37\n\x05Hello\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12@\n\rStartInstance\x12\x16.CreateInstanceRequest\x1a\x17.CreateInstanceResponse\x12\x38\n\x0bGetInstance\x12\x13.GetInstanceRequest\x1a\x14.GetInstanceResponse\x12\x41\n\x14WaitForInstanceStart\x12\x13.GetInstanceRequest\x1a\x14.GetInstanceResponse\x12\x46\n\x19WaitForInstanceCompletion\x12\x13.GetInstanceRequest\x1a\x14.GetInstanceResponse\x12\x35\n\nRaiseEvent\x12\x12.RaiseEventRequest\x1a\x13.RaiseEventResponse\x12:\n\x11TerminateInstance\x12\x11.TerminateRequest\x1a\x12.TerminateResponse\x12\x34\n\x0fSuspendInstance\x12\x0f.SuspendRequest\x1a\x10.SuspendResponse\x12\x31\n\x0eResumeInstance\x12\x0e.ResumeRequest\x1a\x0f.ResumeResponse\x12\x41\n\x0ePurgeInstances\x12\x16.PurgeInstancesRequest\x1a\x17.PurgeInstancesResponse\x12\x31\n\x0cGetWorkItems\x12\x14.GetWorkItemsRequest\x1a\t.WorkItem0\x01\x12@\n\x14\x43ompleteActivityTask\x12\x11.ActivityResponse\x1a\x15.CompleteTaskResponse\x12I\n\x18\x43ompleteOrchestratorTask\x12\x11.WorkflowResponse\x1a\x15.CompleteTaskResponse\"\x03\x88\x02\x01\x12@\n\x14\x43ompleteWorkflowTask\x12\x11.WorkflowResponse\x1a\x15.CompleteTaskResponse\x12Y\n\x16RerunWorkflowFromEvent\x12\x1e.RerunWorkflowFromEventRequest\x1a\x1f.RerunWorkflowFromEventResponse\x12\x44\n\x0fListInstanceIDs\x12\x17.ListInstanceIDsRequest\x1a\x18.ListInstanceIDsResponse\x12M\n\x12GetInstanceHistory\x12\x1a.GetInstanceHistoryRequest\x1a\x1b.GetInstanceHistoryResponseBV\n+io.dapr.durabletask.implementation.protobufZ\x0b/api/protos\xaa\x02\x19\x44\x61pr.DurableTask.Protobufb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -42,8 +42,8 @@ _globals['_CREATEINSTANCEREQUEST_TAGSENTRY']._serialized_options = b'8\001' _globals['_TASKHUBSIDECARSERVICE'].methods_by_name['CompleteOrchestratorTask']._loaded_options = None _globals['_TASKHUBSIDECARSERVICE'].methods_by_name['CompleteOrchestratorTask']._serialized_options = b'\210\002\001' - _globals['_WORKERCAPABILITY']._serialized_start=3814 - _globals['_WORKERCAPABILITY']._serialized_end=3950 + _globals['_WORKERCAPABILITY']._serialized_start=4209 + _globals['_WORKERCAPABILITY']._serialized_end=4345 _globals['_ACTIVITYREQUEST']._serialized_start=196 _globals['_ACTIVITYREQUEST']._serialized_end=522 _globals['_ACTIVITYRESPONSE']._serialized_start=525 @@ -55,55 +55,55 @@ _globals['_WORKFLOWRESPONSE']._serialized_start=1116 _globals['_WORKFLOWRESPONSE']._serialized_end=1374 _globals['_CREATEINSTANCEREQUEST']._serialized_start=1377 - _globals['_CREATEINSTANCEREQUEST']._serialized_end=1808 - _globals['_CREATEINSTANCEREQUEST_TAGSENTRY']._serialized_start=1731 - _globals['_CREATEINSTANCEREQUEST_TAGSENTRY']._serialized_end=1774 - _globals['_CREATEINSTANCERESPONSE']._serialized_start=1810 - _globals['_CREATEINSTANCERESPONSE']._serialized_end=1854 - _globals['_GETINSTANCEREQUEST']._serialized_start=1856 - _globals['_GETINSTANCEREQUEST']._serialized_end=1925 - _globals['_GETINSTANCERESPONSE']._serialized_start=1927 - _globals['_GETINSTANCERESPONSE']._serialized_end=2003 - _globals['_RAISEEVENTREQUEST']._serialized_start=2005 - _globals['_RAISEEVENTREQUEST']._serialized_end=2103 - _globals['_RAISEEVENTRESPONSE']._serialized_start=2105 - _globals['_RAISEEVENTRESPONSE']._serialized_end=2125 - _globals['_TERMINATEREQUEST']._serialized_start=2127 - _globals['_TERMINATEREQUEST']._serialized_end=2230 - _globals['_TERMINATERESPONSE']._serialized_start=2232 - _globals['_TERMINATERESPONSE']._serialized_end=2251 - _globals['_SUSPENDREQUEST']._serialized_start=2253 - _globals['_SUSPENDREQUEST']._serialized_end=2335 - _globals['_SUSPENDRESPONSE']._serialized_start=2337 - _globals['_SUSPENDRESPONSE']._serialized_end=2354 - _globals['_RESUMEREQUEST']._serialized_start=2356 - _globals['_RESUMEREQUEST']._serialized_end=2437 - _globals['_RESUMERESPONSE']._serialized_start=2439 - _globals['_RESUMERESPONSE']._serialized_end=2455 - _globals['_PURGEINSTANCESREQUEST']._serialized_start=2458 - _globals['_PURGEINSTANCESREQUEST']._serialized_end=2616 - _globals['_PURGEINSTANCEFILTER']._serialized_start=2619 - _globals['_PURGEINSTANCEFILTER']._serialized_end=2789 - _globals['_PURGEINSTANCESRESPONSE']._serialized_start=2791 - _globals['_PURGEINSTANCESRESPONSE']._serialized_end=2893 - _globals['_GETWORKITEMSREQUEST']._serialized_start=2895 - _globals['_GETWORKITEMSREQUEST']._serialized_end=2981 - _globals['_WORKITEM']._serialized_start=2984 - _globals['_WORKITEM']._serialized_end=3138 - _globals['_COMPLETETASKRESPONSE']._serialized_start=3140 - _globals['_COMPLETETASKRESPONSE']._serialized_end=3162 - _globals['_RERUNWORKFLOWFROMEVENTREQUEST']._serialized_start=3165 - _globals['_RERUNWORKFLOWFROMEVENTREQUEST']._serialized_end=3426 - _globals['_RERUNWORKFLOWFROMEVENTRESPONSE']._serialized_start=3428 - _globals['_RERUNWORKFLOWFROMEVENTRESPONSE']._serialized_end=3483 - _globals['_LISTINSTANCEIDSREQUEST']._serialized_start=3485 - _globals['_LISTINSTANCEIDSREQUEST']._serialized_end=3599 - _globals['_LISTINSTANCEIDSRESPONSE']._serialized_start=3601 - _globals['_LISTINSTANCEIDSRESPONSE']._serialized_end=3701 - _globals['_GETINSTANCEHISTORYREQUEST']._serialized_start=3703 - _globals['_GETINSTANCEHISTORYREQUEST']._serialized_end=3750 - _globals['_GETINSTANCEHISTORYRESPONSE']._serialized_start=3752 - _globals['_GETINSTANCEHISTORYRESPONSE']._serialized_end=3811 - _globals['_TASKHUBSIDECARSERVICE']._serialized_start=3953 - _globals['_TASKHUBSIDECARSERVICE']._serialized_end=5081 + _globals['_CREATEINSTANCEREQUEST']._serialized_end=1886 + _globals['_CREATEINSTANCEREQUEST_TAGSENTRY']._serialized_start=1798 + _globals['_CREATEINSTANCEREQUEST_TAGSENTRY']._serialized_end=1841 + _globals['_CREATEINSTANCERESPONSE']._serialized_start=1888 + _globals['_CREATEINSTANCERESPONSE']._serialized_end=1932 + _globals['_GETINSTANCEREQUEST']._serialized_start=1934 + _globals['_GETINSTANCEREQUEST']._serialized_end=2048 + _globals['_GETINSTANCERESPONSE']._serialized_start=2050 + _globals['_GETINSTANCERESPONSE']._serialized_end=2126 + _globals['_RAISEEVENTREQUEST']._serialized_start=2129 + _globals['_RAISEEVENTREQUEST']._serialized_end=2272 + _globals['_RAISEEVENTRESPONSE']._serialized_start=2274 + _globals['_RAISEEVENTRESPONSE']._serialized_end=2294 + _globals['_TERMINATEREQUEST']._serialized_start=2297 + _globals['_TERMINATEREQUEST']._serialized_end=2445 + _globals['_TERMINATERESPONSE']._serialized_start=2447 + _globals['_TERMINATERESPONSE']._serialized_end=2466 + _globals['_SUSPENDREQUEST']._serialized_start=2468 + _globals['_SUSPENDREQUEST']._serialized_end=2595 + _globals['_SUSPENDRESPONSE']._serialized_start=2597 + _globals['_SUSPENDRESPONSE']._serialized_end=2614 + _globals['_RESUMEREQUEST']._serialized_start=2616 + _globals['_RESUMEREQUEST']._serialized_end=2742 + _globals['_RESUMERESPONSE']._serialized_start=2744 + _globals['_RESUMERESPONSE']._serialized_end=2760 + _globals['_PURGEINSTANCESREQUEST']._serialized_start=2763 + _globals['_PURGEINSTANCESREQUEST']._serialized_end=2966 + _globals['_PURGEINSTANCEFILTER']._serialized_start=2969 + _globals['_PURGEINSTANCEFILTER']._serialized_end=3139 + _globals['_PURGEINSTANCESRESPONSE']._serialized_start=3141 + _globals['_PURGEINSTANCESRESPONSE']._serialized_end=3243 + _globals['_GETWORKITEMSREQUEST']._serialized_start=3245 + _globals['_GETWORKITEMSREQUEST']._serialized_end=3331 + _globals['_WORKITEM']._serialized_start=3334 + _globals['_WORKITEM']._serialized_end=3488 + _globals['_COMPLETETASKRESPONSE']._serialized_start=3490 + _globals['_COMPLETETASKRESPONSE']._serialized_end=3512 + _globals['_RERUNWORKFLOWFROMEVENTREQUEST']._serialized_start=3515 + _globals['_RERUNWORKFLOWFROMEVENTREQUEST']._serialized_end=3821 + _globals['_RERUNWORKFLOWFROMEVENTRESPONSE']._serialized_start=3823 + _globals['_RERUNWORKFLOWFROMEVENTRESPONSE']._serialized_end=3878 + _globals['_LISTINSTANCEIDSREQUEST']._serialized_start=3880 + _globals['_LISTINSTANCEIDSREQUEST']._serialized_end=3994 + _globals['_LISTINSTANCEIDSRESPONSE']._serialized_start=3996 + _globals['_LISTINSTANCEIDSRESPONSE']._serialized_end=4096 + _globals['_GETINSTANCEHISTORYREQUEST']._serialized_start=4098 + _globals['_GETINSTANCEHISTORYREQUEST']._serialized_end=4145 + _globals['_GETINSTANCEHISTORYRESPONSE']._serialized_start=4147 + _globals['_GETINSTANCEHISTORYRESPONSE']._serialized_end=4206 + _globals['_TASKHUBSIDECARSERVICE']._serialized_start=4348 + _globals['_TASKHUBSIDECARSERVICE']._serialized_end=5476 # @@protoc_insertion_point(module_scope) diff --git a/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi b/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi index dcce421a4..f0064bd6b 100644 --- a/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi +++ b/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi @@ -322,8 +322,15 @@ class CreateInstanceRequest(_message.Message): EXECUTIONID_FIELD_NUMBER: _builtins.int TAGS_FIELD_NUMBER: _builtins.int PARENTTRACECONTEXT_FIELD_NUMBER: _builtins.int + ENFORCEUNIQUEINSTANCEID_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str name: _builtins.str + enforceUniqueInstanceId: _builtins.bool + """When true, the request fails with an ALREADY_EXISTS error if a workflow + instance with the same instanceId already exists, whether active or + completed. When false, an existing completed instance is restarted. + """ @_builtins.property def version(self) -> _wrappers_pb2.StringValue: ... @_builtins.property @@ -336,6 +343,15 @@ class CreateInstanceRequest(_message.Message): def tags(self) -> _containers.ScalarMap[_builtins.str, _builtins.str]: ... @_builtins.property def parentTraceContext(self) -> _orchestration_pb2.TraceContext: ... + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. When targetAppID names a different app, the operation is + executed against that app's instance (same namespace unless + targetAppNamespace is set). sourceAppID is stamped by the sidecar, not + the client. + """ + def __init__( self, *, @@ -347,11 +363,16 @@ class CreateInstanceRequest(_message.Message): executionId: _wrappers_pb2.StringValue | None = ..., tags: _abc.Mapping[_builtins.str, _builtins.str] | None = ..., parentTraceContext: _orchestration_pb2.TraceContext | None = ..., + enforceUniqueInstanceId: _builtins.bool = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["executionId", b"executionId", "input", b"input", "parentTraceContext", b"parentTraceContext", "scheduledStartTimestamp", b"scheduledStartTimestamp", "version", b"version"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "executionId", b"executionId", "input", b"input", "parentTraceContext", b"parentTraceContext", "router", b"router", "scheduledStartTimestamp", b"scheduledStartTimestamp", "version", b"version"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["executionId", b"executionId", "input", b"input", "instanceId", b"instanceId", "name", b"name", "parentTraceContext", b"parentTraceContext", "scheduledStartTimestamp", b"scheduledStartTimestamp", "tags", b"tags", "version", b"version"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "enforceUniqueInstanceId", b"enforceUniqueInstanceId", "executionId", b"executionId", "input", b"input", "instanceId", b"instanceId", "name", b"name", "parentTraceContext", b"parentTraceContext", "router", b"router", "scheduledStartTimestamp", b"scheduledStartTimestamp", "tags", b"tags", "version", b"version"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___CreateInstanceRequest: _TypeAlias = CreateInstanceRequest # noqa: Y015 @@ -377,16 +398,29 @@ class GetInstanceRequest(_message.Message): INSTANCEID_FIELD_NUMBER: _builtins.int GETINPUTSANDOUTPUTS_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str getInputsAndOutputs: _builtins.bool + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. sourceAppID is stamped by the sidecar, not the client. + """ + def __init__( self, *, instanceId: _builtins.str = ..., getInputsAndOutputs: _builtins.bool = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["getInputsAndOutputs", b"getInputsAndOutputs", "instanceId", b"instanceId"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "router", b"router"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "getInputsAndOutputs", b"getInputsAndOutputs", "instanceId", b"instanceId", "router", b"router"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___GetInstanceRequest: _TypeAlias = GetInstanceRequest # noqa: Y015 @@ -419,21 +453,32 @@ class RaiseEventRequest(_message.Message): INSTANCEID_FIELD_NUMBER: _builtins.int NAME_FIELD_NUMBER: _builtins.int INPUT_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str name: _builtins.str @_builtins.property def input(self) -> _wrappers_pb2.StringValue: ... + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. sourceAppID is stamped by the sidecar, not the client. + """ + def __init__( self, *, instanceId: _builtins.str = ..., name: _builtins.str = ..., input: _wrappers_pb2.StringValue | None = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["input", b"input"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "input", b"input", "router", b"router"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["input", b"input", "instanceId", b"instanceId", "name", b"name"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "input", b"input", "instanceId", b"instanceId", "name", b"name", "router", b"router"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___RaiseEventRequest: _TypeAlias = RaiseEventRequest # noqa: Y015 @@ -456,21 +501,32 @@ class TerminateRequest(_message.Message): INSTANCEID_FIELD_NUMBER: _builtins.int OUTPUT_FIELD_NUMBER: _builtins.int RECURSIVE_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str recursive: _builtins.bool @_builtins.property def output(self) -> _wrappers_pb2.StringValue: ... + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. sourceAppID is stamped by the sidecar, not the client. + """ + def __init__( self, *, instanceId: _builtins.str = ..., output: _wrappers_pb2.StringValue | None = ..., recursive: _builtins.bool = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["output", b"output"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "output", b"output", "router", b"router"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["instanceId", b"instanceId", "output", b"output", "recursive", b"recursive"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "instanceId", b"instanceId", "output", b"output", "recursive", b"recursive", "router", b"router"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___TerminateRequest: _TypeAlias = TerminateRequest # noqa: Y015 @@ -492,19 +548,30 @@ class SuspendRequest(_message.Message): INSTANCEID_FIELD_NUMBER: _builtins.int REASON_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str @_builtins.property def reason(self) -> _wrappers_pb2.StringValue: ... + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. sourceAppID is stamped by the sidecar, not the client. + """ + def __init__( self, *, instanceId: _builtins.str = ..., reason: _wrappers_pb2.StringValue | None = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["reason", b"reason"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "reason", b"reason", "router", b"router"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["instanceId", b"instanceId", "reason", b"reason"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "instanceId", b"instanceId", "reason", b"reason", "router", b"router"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___SuspendRequest: _TypeAlias = SuspendRequest # noqa: Y015 @@ -526,19 +593,30 @@ class ResumeRequest(_message.Message): INSTANCEID_FIELD_NUMBER: _builtins.int REASON_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str @_builtins.property def reason(self) -> _wrappers_pb2.StringValue: ... + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. sourceAppID is stamped by the sidecar, not the client. + """ + def __init__( self, *, instanceId: _builtins.str = ..., reason: _wrappers_pb2.StringValue | None = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["reason", b"reason"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "reason", b"reason", "router", b"router"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["instanceId", b"instanceId", "reason", b"reason"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_router", b"_router", "instanceId", b"instanceId", "reason", b"reason", "router", b"router"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___ResumeRequest: _TypeAlias = ResumeRequest # noqa: Y015 @@ -562,6 +640,7 @@ class PurgeInstancesRequest(_message.Message): PURGEINSTANCEFILTER_FIELD_NUMBER: _builtins.int RECURSIVE_FIELD_NUMBER: _builtins.int FORCE_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int instanceId: _builtins.str recursive: _builtins.bool force: _builtins.bool @@ -577,6 +656,14 @@ class PurgeInstancesRequest(_message.Message): """ @_builtins.property def purgeInstanceFilter(self) -> Global___PurgeInstanceFilter: ... + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. The purge is delegated to the target app, which honours + the caller's recursive flag. sourceAppID is stamped by the sidecar, not + the client. + """ + def __init__( self, *, @@ -584,18 +671,23 @@ class PurgeInstancesRequest(_message.Message): purgeInstanceFilter: Global___PurgeInstanceFilter | None = ..., recursive: _builtins.bool = ..., force: _builtins.bool | None = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["_force", b"_force", "force", b"force", "instanceId", b"instanceId", "purgeInstanceFilter", b"purgeInstanceFilter", "request", b"request"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_force", b"_force", "_router", b"_router", "force", b"force", "instanceId", b"instanceId", "purgeInstanceFilter", b"purgeInstanceFilter", "request", b"request", "router", b"router"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["_force", b"_force", "force", b"force", "instanceId", b"instanceId", "purgeInstanceFilter", b"purgeInstanceFilter", "recursive", b"recursive", "request", b"request"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_force", b"_force", "_router", b"_router", "force", b"force", "instanceId", b"instanceId", "purgeInstanceFilter", b"purgeInstanceFilter", "recursive", b"recursive", "request", b"request", "router", b"router"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... _WhichOneofReturnType__force: _TypeAlias = _typing.Literal["force"] # noqa: Y015 _WhichOneofArgType__force: _TypeAlias = _typing.Literal["_force", b"_force"] # noqa: Y015 + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 _WhichOneofReturnType_request: _TypeAlias = _typing.Literal["instanceId", "purgeInstanceFilter"] # noqa: Y015 _WhichOneofArgType_request: _TypeAlias = _typing.Literal["request", b"request"] # noqa: Y015 @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__force) -> _WhichOneofReturnType__force | None: ... @_typing.overload + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... + @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType_request) -> _WhichOneofReturnType_request | None: ... Global___PurgeInstancesRequest: _TypeAlias = PurgeInstancesRequest # noqa: Y015 @@ -727,6 +819,7 @@ class RerunWorkflowFromEventRequest(_message.Message): INPUT_FIELD_NUMBER: _builtins.int OVERWRITEINPUT_FIELD_NUMBER: _builtins.int NEWCHILDWORKFLOWINSTANCEID_FIELD_NUMBER: _builtins.int + ROUTER_FIELD_NUMBER: _builtins.int sourceInstanceID: _builtins.str """sourceInstanceID is the workflow instance ID to rerun. Can be a top level instance, or child workflow instance. @@ -754,6 +847,12 @@ class RerunWorkflowFromEventRequest(_message.Message): the next Activity event. """ + @_builtins.property + def router(self) -> _orchestration_pb2.TaskRouter: + """router optionally routes this operation to the workflow instance owned + by another app. sourceAppID is stamped by the sidecar, not the client. + """ + def __init__( self, *, @@ -763,19 +862,24 @@ class RerunWorkflowFromEventRequest(_message.Message): input: _wrappers_pb2.StringValue | None = ..., overwriteInput: _builtins.bool = ..., newChildWorkflowInstanceID: _builtins.str | None = ..., + router: _orchestration_pb2.TaskRouter | None = ..., ) -> None: ... - _HasFieldArgType: _TypeAlias = _typing.Literal["_newChildWorkflowInstanceID", b"_newChildWorkflowInstanceID", "_newInstanceID", b"_newInstanceID", "input", b"input", "newChildWorkflowInstanceID", b"newChildWorkflowInstanceID", "newInstanceID", b"newInstanceID"] # noqa: Y015 + _HasFieldArgType: _TypeAlias = _typing.Literal["_newChildWorkflowInstanceID", b"_newChildWorkflowInstanceID", "_newInstanceID", b"_newInstanceID", "_router", b"_router", "input", b"input", "newChildWorkflowInstanceID", b"newChildWorkflowInstanceID", "newInstanceID", b"newInstanceID", "router", b"router"] # noqa: Y015 def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... - _ClearFieldArgType: _TypeAlias = _typing.Literal["_newChildWorkflowInstanceID", b"_newChildWorkflowInstanceID", "_newInstanceID", b"_newInstanceID", "eventID", b"eventID", "input", b"input", "newChildWorkflowInstanceID", b"newChildWorkflowInstanceID", "newInstanceID", b"newInstanceID", "overwriteInput", b"overwriteInput", "sourceInstanceID", b"sourceInstanceID"] # noqa: Y015 + _ClearFieldArgType: _TypeAlias = _typing.Literal["_newChildWorkflowInstanceID", b"_newChildWorkflowInstanceID", "_newInstanceID", b"_newInstanceID", "_router", b"_router", "eventID", b"eventID", "input", b"input", "newChildWorkflowInstanceID", b"newChildWorkflowInstanceID", "newInstanceID", b"newInstanceID", "overwriteInput", b"overwriteInput", "router", b"router", "sourceInstanceID", b"sourceInstanceID"] # noqa: Y015 def ClearField(self, field_name: _ClearFieldArgType) -> None: ... _WhichOneofReturnType__newChildWorkflowInstanceID: _TypeAlias = _typing.Literal["newChildWorkflowInstanceID"] # noqa: Y015 _WhichOneofArgType__newChildWorkflowInstanceID: _TypeAlias = _typing.Literal["_newChildWorkflowInstanceID", b"_newChildWorkflowInstanceID"] # noqa: Y015 _WhichOneofReturnType__newInstanceID: _TypeAlias = _typing.Literal["newInstanceID"] # noqa: Y015 _WhichOneofArgType__newInstanceID: _TypeAlias = _typing.Literal["_newInstanceID", b"_newInstanceID"] # noqa: Y015 + _WhichOneofReturnType__router: _TypeAlias = _typing.Literal["router"] # noqa: Y015 + _WhichOneofArgType__router: _TypeAlias = _typing.Literal["_router", b"_router"] # noqa: Y015 @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__newChildWorkflowInstanceID) -> _WhichOneofReturnType__newChildWorkflowInstanceID | None: ... @_typing.overload def WhichOneof(self, oneof_group: _WhichOneofArgType__newInstanceID) -> _WhichOneofReturnType__newInstanceID | None: ... + @_typing.overload + def WhichOneof(self, oneof_group: _WhichOneofArgType__router) -> _WhichOneofReturnType__router | None: ... Global___RerunWorkflowFromEventRequest: _TypeAlias = RerunWorkflowFromEventRequest # noqa: Y015 diff --git a/dapr/ext/workflow/aio/dapr_workflow_client.py b/dapr/ext/workflow/aio/dapr_workflow_client.py index 8a6072cf2..552ec35f2 100644 --- a/dapr/ext/workflow/aio/dapr_workflow_client.py +++ b/dapr/ext/workflow/aio/dapr_workflow_client.py @@ -98,6 +98,7 @@ async def schedule_new_workflow( instance_id: Optional[str] = None, start_at: Optional[datetime] = None, reuse_id_policy: Optional[client.WorkflowIdReusePolicy] = None, + app_id: Optional[str] = None, ) -> str: """Schedules a new workflow instance for execution. @@ -113,6 +114,10 @@ async def schedule_new_workflow( reuse_id_policy: Deprecated and has no effect; it will be removed in a future release. A workflow instance ID can always be reused once the existing instance with that ID has reached a terminal state (e.g. COMPLETED, FAILED, or TERMINATED). + app_id: The optional ID of another app to schedule the workflow on. The target + app's WorkflowAccessPolicy governs whether this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: The ID of the scheduled workflow instance. @@ -138,10 +143,15 @@ async def schedule_new_workflow( instance_id=instance_id, start_at=start_at, reuse_id_policy=reuse_id_policy, + app_id=app_id, ) async def get_workflow_state( - self, instance_id: str, *, fetch_payloads: bool = True + self, + instance_id: str, + *, + fetch_payloads: bool = True, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: """Fetches runtime state for the specified workflow instance. @@ -149,6 +159,11 @@ async def get_workflow_state( instance_id: The unique ID of the workflow instance to fetch. fetch_payloads: If true, fetches the input, output payloads and custom status for the workflow instance. Defaults to true. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: The current state of the workflow instance, or None if the workflow instance does not @@ -157,7 +172,9 @@ async def get_workflow_state( """ try: state = await self.__obj.get_orchestration_state( - instance_id, fetch_payloads=fetch_payloads + instance_id, + fetch_payloads=fetch_payloads, + app_id=app_id, ) return WorkflowState(state) if state else None except AioRpcError as error: @@ -170,7 +187,12 @@ async def get_workflow_state( raise async def wait_for_workflow_start( - self, instance_id: str, *, fetch_payloads: bool = False, timeout_in_seconds: int = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = False, + timeout_in_seconds: int = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: """Waits for a workflow to start running and returns a WorkflowState object that contains metadata about the started workflow. @@ -185,18 +207,31 @@ async def wait_for_workflow_start( the workflow instance. Defaults to false. timeout_in_seconds: The maximum time to wait for the workflow instance to start running. Defaults to meaning no timeout. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: WorkflowState record that describes the workflow instance and its execution status. If the specified workflow isn't found, the WorkflowState.Exists value will be false. """ state = await self.__obj.wait_for_orchestration_start( - instance_id, fetch_payloads=fetch_payloads, timeout=timeout_in_seconds + instance_id, + fetch_payloads=fetch_payloads, + timeout=timeout_in_seconds, + app_id=app_id, ) return WorkflowState(state) if state else None async def wait_for_workflow_completion( - self, instance_id: str, *, fetch_payloads: bool = True, timeout_in_seconds: int = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = True, + timeout_in_seconds: int = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: """Waits for a workflow to complete and returns a WorkflowState object that contains metadata about the started instance. @@ -219,17 +254,30 @@ async def wait_for_workflow_completion( for the workflow instance. Defaults to true. timeout_in_seconds: The maximum time in seconds to wait for the workflow instance to complete. Defaults to 0 seconds, meaning no timeout. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: WorkflowState record that describes the workflow instance and its execution status. """ state = await self.__obj.wait_for_orchestration_completion( - instance_id, fetch_payloads=fetch_payloads, timeout=timeout_in_seconds + instance_id, + fetch_payloads=fetch_payloads, + timeout=timeout_in_seconds, + app_id=app_id, ) return WorkflowState(state) if state else None async def raise_workflow_event( - self, instance_id: str, event_name: str, *, data: Optional[Any] = None + self, + instance_id: str, + event_name: str, + *, + data: Optional[Any] = None, + app_id: Optional[str] = None, ) -> None: """Sends an event notification message to a waiting workflow instance. In order to handle the event, the target workflow instance must be waiting for an @@ -251,11 +299,23 @@ async def raise_workflow_event( instance_id: The ID of the workflow instance that will handle the event. event_name: The name of the event. Event names are case-insensitive. data: The serializable data payload to include with the event. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return await self.__obj.raise_orchestration_event(instance_id, event_name, data=data) + return await self.__obj.raise_orchestration_event( + instance_id, event_name, data=data, app_id=app_id + ) async def terminate_workflow( - self, instance_id: str, *, output: Optional[Any] = None, recursive: bool = True + self, + instance_id: str, + *, + output: Optional[Any] = None, + recursive: bool = True, + app_id: Optional[str] = None, ) -> None: """Terminates a running workflow instance and updates its runtime status to WorkflowRuntimeStatus.Terminated This method internally enqueues a "terminate" message in @@ -275,34 +335,73 @@ async def terminate_workflow( instance_id: The ID of the workflow instance to terminate. output: The optional output to set for the terminated workflow instance. recursive: The optional flag to terminate all child workflows. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ return await self.__obj.terminate_orchestration( - instance_id, output=output, recursive=recursive + instance_id, + output=output, + recursive=recursive, + app_id=app_id, ) - async def pause_workflow(self, instance_id: str) -> None: + async def pause_workflow( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ) -> None: """Suspends a workflow instance, halting processing of it until resume_workflow is used to resume the workflow. Args: instance_id: The instance ID of the workflow to suspend. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return await self.__obj.suspend_orchestration(instance_id) + return await self.__obj.suspend_orchestration(instance_id, app_id=app_id) - async def resume_workflow(self, instance_id: str) -> None: + async def resume_workflow( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ) -> None: """Resumes a workflow instance that was suspended via pause_workflow. Args: instance_id: The instance ID of the workflow to resume. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return await self.__obj.resume_orchestration(instance_id) + return await self.__obj.resume_orchestration(instance_id, app_id=app_id) - async def purge_workflow(self, instance_id: str, recursive: bool = True) -> None: + async def purge_workflow( + self, + instance_id: str, + recursive: bool = True, + *, + app_id: Optional[str] = None, + ) -> None: """Purge data from a workflow instance. Args: instance_id: The instance ID of the workflow to purge. recursive: The optional flag to also purge data from all child workflows. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return await self.__obj.purge_orchestration(instance_id, recursive) + return await self.__obj.purge_orchestration(instance_id, recursive, app_id=app_id) diff --git a/dapr/ext/workflow/dapr_workflow_client.py b/dapr/ext/workflow/dapr_workflow_client.py index dca65c200..02be04f88 100644 --- a/dapr/ext/workflow/dapr_workflow_client.py +++ b/dapr/ext/workflow/dapr_workflow_client.py @@ -100,6 +100,7 @@ def schedule_new_workflow( instance_id: Optional[str] = None, start_at: Optional[datetime] = None, reuse_id_policy: Optional[client.WorkflowIdReusePolicy] = None, + app_id: Optional[str] = None, ) -> str: """Schedules a new workflow instance for execution. @@ -115,6 +116,10 @@ def schedule_new_workflow( reuse_id_policy: Deprecated and has no effect; it will be removed in a future release. A workflow instance ID can always be reused once the existing instance with that ID has reached a terminal state (e.g. COMPLETED, FAILED, or TERMINATED). + app_id: The optional ID of another app to schedule the workflow on. The target + app's WorkflowAccessPolicy governs whether this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: The ID of the scheduled workflow instance. @@ -140,10 +145,15 @@ def schedule_new_workflow( instance_id=instance_id, start_at=start_at, reuse_id_policy=reuse_id_policy, + app_id=app_id, ) def get_workflow_state( - self, instance_id: str, *, fetch_payloads: bool = True + self, + instance_id: str, + *, + fetch_payloads: bool = True, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: """Fetches runtime state for the specified workflow instance. @@ -151,6 +161,11 @@ def get_workflow_state( instance_id: The unique ID of the workflow instance to fetch. fetch_payloads: If true, fetches the input, output payloads and custom status for the workflow instance. Defaults to true. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: The current state of the workflow instance, or None if the workflow instance does not @@ -158,7 +173,11 @@ def get_workflow_state( """ try: - state = self.__obj.get_orchestration_state(instance_id, fetch_payloads=fetch_payloads) + state = self.__obj.get_orchestration_state( + instance_id, + fetch_payloads=fetch_payloads, + app_id=app_id, + ) return WorkflowState(state) if state else None except RpcError as error: if 'no such instance exists' in error.details(): @@ -170,7 +189,12 @@ def get_workflow_state( raise def wait_for_workflow_start( - self, instance_id: str, *, fetch_payloads: bool = False, timeout_in_seconds: int = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = False, + timeout_in_seconds: int = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: """Waits for a workflow to start running and returns a WorkflowState object that contains metadata about the started workflow. @@ -185,18 +209,31 @@ def wait_for_workflow_start( the workflow instance. Defaults to false. timeout_in_seconds: The maximum time to wait for the workflow instance to start running. Defaults to meaning no timeout. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: WorkflowState record that describes the workflow instance and its execution status. If the specified workflow isn't found, the WorkflowState.Exists value will be false. """ state = self.__obj.wait_for_orchestration_start( - instance_id, fetch_payloads=fetch_payloads, timeout=timeout_in_seconds + instance_id, + fetch_payloads=fetch_payloads, + timeout=timeout_in_seconds, + app_id=app_id, ) return WorkflowState(state) if state else None def wait_for_workflow_completion( - self, instance_id: str, *, fetch_payloads: bool = True, timeout_in_seconds: int = 0 + self, + instance_id: str, + *, + fetch_payloads: bool = True, + timeout_in_seconds: int = 0, + app_id: Optional[str] = None, ) -> Optional[WorkflowState]: """Waits for a workflow to complete and returns a WorkflowState object that contains metadata about the started instance. @@ -219,17 +256,30 @@ def wait_for_workflow_completion( for the workflow instance. Defaults to true. timeout_in_seconds: The maximum time in seconds to wait for the workflow instance to complete. Defaults to 0 seconds, meaning no timeout. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. Returns: WorkflowState record that describes the workflow instance and its execution status. """ state = self.__obj.wait_for_orchestration_completion( - instance_id, fetch_payloads=fetch_payloads, timeout=timeout_in_seconds + instance_id, + fetch_payloads=fetch_payloads, + timeout=timeout_in_seconds, + app_id=app_id, ) return WorkflowState(state) if state else None def raise_workflow_event( - self, instance_id: str, event_name: str, *, data: Optional[Any] = None + self, + instance_id: str, + event_name: str, + *, + data: Optional[Any] = None, + app_id: Optional[str] = None, ): """Sends an event notification message to a waiting workflow instance. In order to handle the event, the target workflow instance must be waiting for an @@ -251,11 +301,23 @@ def raise_workflow_event( instance_id: The ID of the workflow instance that will handle the event. event_name: The name of the event. Event names are case-insensitive. data: The serializable data payload to include with the event. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return self.__obj.raise_orchestration_event(instance_id, event_name, data=data) + return self.__obj.raise_orchestration_event( + instance_id, event_name, data=data, app_id=app_id + ) def terminate_workflow( - self, instance_id: str, *, output: Optional[Any] = None, recursive: bool = True + self, + instance_id: str, + *, + output: Optional[Any] = None, + recursive: bool = True, + app_id: Optional[str] = None, ): """Terminates a running workflow instance and updates its runtime status to WorkflowRuntimeStatus.Terminated This method internally enqueues a "terminate" message in @@ -275,35 +337,76 @@ def terminate_workflow( instance_id: The ID of the workflow instance to terminate. output: The optional output to set for the terminated workflow instance. recursive: The optional flag to terminate all child workflows. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return self.__obj.terminate_orchestration(instance_id, output=output, recursive=recursive) + return self.__obj.terminate_orchestration( + instance_id, + output=output, + recursive=recursive, + app_id=app_id, + ) - def pause_workflow(self, instance_id: str): + def pause_workflow( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ): """Suspends a workflow instance, halting processing of it until resume_workflow is used to resume the workflow. Args: instance_id: The instance ID of the workflow to suspend. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return self.__obj.suspend_orchestration(instance_id) + return self.__obj.suspend_orchestration(instance_id, app_id=app_id) - def resume_workflow(self, instance_id: str): + def resume_workflow( + self, + instance_id: str, + *, + app_id: Optional[str] = None, + ): """Resumes a workflow instance that was suspended via pause_workflow. Args: instance_id: The instance ID of the workflow to resume. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return self.__obj.resume_orchestration(instance_id) + return self.__obj.resume_orchestration(instance_id, app_id=app_id) - def purge_workflow(self, instance_id: str, recursive: bool = True): + def purge_workflow( + self, + instance_id: str, + recursive: bool = True, + *, + app_id: Optional[str] = None, + ): """Purge data from a workflow instance. Args: instance_id: The instance ID of the workflow to purge. recursive: The optional flag to also purge data from all child workflows. + app_id: The optional ID of the app hosting the workflow instance, when it is + hosted by a different app. The target app's WorkflowAccessPolicy governs whether + this operation is permitted. + Requires a Dapr runtime with cross-app workflow support; older runtimes + ignore app_id and apply the operation to the local app. """ - return self.__obj.purge_orchestration(instance_id, recursive) + return self.__obj.purge_orchestration(instance_id, recursive, app_id=app_id) def close(self): """Closes the gRPC connection used by the client.""" diff --git a/tests/ext/workflow/durabletask/test_client_routing.py b/tests/ext/workflow/durabletask/test_client_routing.py new file mode 100644 index 000000000..414f26da0 --- /dev/null +++ b/tests/ext/workflow/durabletask/test_client_routing.py @@ -0,0 +1,195 @@ +# Copyright 2026 The Dapr Authors +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for cross-app routing (TaskRouter) support in the durabletask clients.""" + +from unittest.mock import AsyncMock, MagicMock, patch + +import dapr.ext.workflow._durabletask.internal.protos as pb +from dapr.ext.workflow._durabletask.aio.client import AsyncTaskHubGrpcClient +from dapr.ext.workflow._durabletask.client import TaskHubGrpcClient, new_task_router + +TARGET_APP_ID = 'appB' +INSTANCE_ID = 'instance001' + + +def _make_sync_client() -> TaskHubGrpcClient: + with patch('grpc.insecure_channel'): + hub_client = TaskHubGrpcClient(host_address='localhost:1') + stub = MagicMock() + stub.StartInstance.return_value = pb.CreateInstanceResponse(instanceId=INSTANCE_ID) + stub.GetInstance.return_value = pb.GetInstanceResponse(exists=False) + stub.WaitForInstanceStart.return_value = pb.GetInstanceResponse(exists=False) + stub.WaitForInstanceCompletion.return_value = pb.GetInstanceResponse(exists=False) + hub_client._stub = stub + return hub_client + + +def _make_async_client() -> AsyncTaskHubGrpcClient: + hub_client = AsyncTaskHubGrpcClient(host_address='localhost:1') + stub = AsyncMock() + stub.StartInstance.return_value = pb.CreateInstanceResponse(instanceId=INSTANCE_ID) + stub.GetInstance.return_value = pb.GetInstanceResponse(exists=False) + stub.WaitForInstanceStart.return_value = pb.GetInstanceResponse(exists=False) + stub.WaitForInstanceCompletion.return_value = pb.GetInstanceResponse(exists=False) + hub_client._stub = stub + return hub_client + + +def _sent_request(stub_method): + return stub_method.call_args[0][0] + + +def _assert_routed(req): + assert req.HasField('router') + assert req.router.targetAppID == TARGET_APP_ID + assert req.router.HasField('targetAppID') + assert req.router.sourceAppID == '' + assert not req.router.HasField('targetAppNamespace') + + +def test_new_task_router_none_when_no_app_id(): + assert new_task_router(None) is None + + +def test_new_task_router_target_app_only(): + router = new_task_router(TARGET_APP_ID) + assert router.targetAppID == TARGET_APP_ID + assert not router.HasField('targetAppNamespace') + assert router.sourceAppID == '' + + +def test_sync_client_sets_router_when_app_id_given(): + hub_client = _make_sync_client() + stub = hub_client._stub + + hub_client.schedule_new_orchestration('wf', app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.StartInstance)) + + hub_client.get_orchestration_state(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.GetInstance)) + + hub_client.wait_for_orchestration_start(INSTANCE_ID, timeout=1, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.WaitForInstanceStart)) + + hub_client.wait_for_orchestration_completion(INSTANCE_ID, timeout=1, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.WaitForInstanceCompletion)) + + hub_client.raise_orchestration_event(INSTANCE_ID, 'event', app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.RaiseEvent)) + + hub_client.terminate_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.TerminateInstance)) + + hub_client.suspend_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.SuspendInstance)) + + hub_client.resume_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.ResumeInstance)) + + hub_client.purge_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.PurgeInstances)) + + +def test_sync_client_no_router_when_app_id_none(): + hub_client = _make_sync_client() + stub = hub_client._stub + + hub_client.schedule_new_orchestration('wf') + assert not _sent_request(stub.StartInstance).HasField('router') + + hub_client.get_orchestration_state(INSTANCE_ID) + assert not _sent_request(stub.GetInstance).HasField('router') + + hub_client.wait_for_orchestration_start(INSTANCE_ID, timeout=1) + assert not _sent_request(stub.WaitForInstanceStart).HasField('router') + + hub_client.wait_for_orchestration_completion(INSTANCE_ID, timeout=1) + assert not _sent_request(stub.WaitForInstanceCompletion).HasField('router') + + hub_client.raise_orchestration_event(INSTANCE_ID, 'event') + assert not _sent_request(stub.RaiseEvent).HasField('router') + + hub_client.terminate_orchestration(INSTANCE_ID) + assert not _sent_request(stub.TerminateInstance).HasField('router') + + hub_client.suspend_orchestration(INSTANCE_ID) + assert not _sent_request(stub.SuspendInstance).HasField('router') + + hub_client.resume_orchestration(INSTANCE_ID) + assert not _sent_request(stub.ResumeInstance).HasField('router') + + hub_client.purge_orchestration(INSTANCE_ID) + assert not _sent_request(stub.PurgeInstances).HasField('router') + + +async def test_async_client_sets_router_when_app_id_given(): + hub_client = _make_async_client() + stub = hub_client._stub + + await hub_client.schedule_new_orchestration('wf', app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.StartInstance)) + + await hub_client.get_orchestration_state(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.GetInstance)) + + await hub_client.wait_for_orchestration_start(INSTANCE_ID, timeout=1, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.WaitForInstanceStart)) + + await hub_client.wait_for_orchestration_completion(INSTANCE_ID, timeout=1, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.WaitForInstanceCompletion)) + + await hub_client.raise_orchestration_event(INSTANCE_ID, 'event', app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.RaiseEvent)) + + await hub_client.terminate_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.TerminateInstance)) + + await hub_client.suspend_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.SuspendInstance)) + + await hub_client.resume_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.ResumeInstance)) + + await hub_client.purge_orchestration(INSTANCE_ID, app_id=TARGET_APP_ID) + _assert_routed(_sent_request(stub.PurgeInstances)) + + +async def test_async_client_no_router_when_app_id_none(): + hub_client = _make_async_client() + stub = hub_client._stub + + await hub_client.schedule_new_orchestration('wf') + assert not _sent_request(stub.StartInstance).HasField('router') + + await hub_client.get_orchestration_state(INSTANCE_ID) + assert not _sent_request(stub.GetInstance).HasField('router') + + await hub_client.wait_for_orchestration_start(INSTANCE_ID, timeout=1) + assert not _sent_request(stub.WaitForInstanceStart).HasField('router') + + await hub_client.wait_for_orchestration_completion(INSTANCE_ID, timeout=1) + assert not _sent_request(stub.WaitForInstanceCompletion).HasField('router') + + await hub_client.raise_orchestration_event(INSTANCE_ID, 'event') + assert not _sent_request(stub.RaiseEvent).HasField('router') + + await hub_client.terminate_orchestration(INSTANCE_ID) + assert not _sent_request(stub.TerminateInstance).HasField('router') + + await hub_client.suspend_orchestration(INSTANCE_ID) + assert not _sent_request(stub.SuspendInstance).HasField('router') + + await hub_client.resume_orchestration(INSTANCE_ID) + assert not _sent_request(stub.ResumeInstance).HasField('router') + + await hub_client.purge_orchestration(INSTANCE_ID) + assert not _sent_request(stub.PurgeInstances).HasField('router') diff --git a/tests/ext/workflow/durabletask/test_orchestration_executor.py b/tests/ext/workflow/durabletask/test_orchestration_executor.py index cdbbbdee0..551d03abb 100644 --- a/tests/ext/workflow/durabletask/test_orchestration_executor.py +++ b/tests/ext/workflow/durabletask/test_orchestration_executor.py @@ -246,7 +246,7 @@ def orchestrator(ctx: task.OrchestrationContext, orchestrator_input): def test_schedule_activity_actions_router_without_app_id(): - """Tests that scheduleTask action contains correct router fields when app_id is specified""" + """Tests that the workflow action carries correct router fields when app_id is specified""" def dummy_activity(ctx, _): pass @@ -274,12 +274,10 @@ def orchestrator(ctx: task.OrchestrationContext, _): action = actions[0] assert action.router.sourceAppID == 'source-app' assert action.router.targetAppID == '' - assert action.scheduleTask.router.sourceAppID == 'source-app' - assert action.scheduleTask.router.targetAppID == '' def test_schedule_activity_actions_router_with_app_id(): - """Tests that scheduleTask action contains correct router fields when app_id is specified""" + """Tests that the workflow action carries correct router fields when app_id is specified""" def dummy_activity(ctx, _): pass @@ -307,8 +305,6 @@ def orchestrator(ctx: task.OrchestrationContext, _): action = actions[0] assert action.router.sourceAppID == 'source-app' assert action.router.targetAppID == 'target-app' - assert action.scheduleTask.router.sourceAppID == 'source-app' - assert action.scheduleTask.router.targetAppID == 'target-app' def test_activity_task_completion(): @@ -771,7 +767,7 @@ def orchestrator(ctx: task.OrchestrationContext, _): def test_create_sub_orchestration_actions_router_without_app_id(): - """Tests that createChildWorkflow action contains correct router fields when app_id is specified""" + """Tests that the workflow action carries correct router fields when app_id is specified""" def suborchestrator(ctx: task.OrchestrationContext, _): pass @@ -801,12 +797,10 @@ def orchestrator(ctx: task.OrchestrationContext, _): action = actions[0] assert action.router.sourceAppID == 'source-app' assert action.router.targetAppID == '' - assert action.createChildWorkflow.router.sourceAppID == 'source-app' - assert action.createChildWorkflow.router.targetAppID == '' def test_create_sub_orchestration_actions_router_with_app_id(): - """Tests that createChildWorkflow action contains correct router fields when app_id is specified""" + """Tests that the workflow action carries correct router fields when app_id is specified""" def suborchestrator(ctx: task.OrchestrationContext, _): pass @@ -836,8 +830,6 @@ def orchestrator(ctx: task.OrchestrationContext, _): action = actions[0] assert action.router.sourceAppID == 'source-app' assert action.router.targetAppID == 'target-app' - assert action.createChildWorkflow.router.sourceAppID == 'source-app' - assert action.createChildWorkflow.router.targetAppID == 'target-app' def test_sub_orchestration_task_failed(): diff --git a/tests/ext/workflow/test_workflow_client.py b/tests/ext/workflow/test_workflow_client.py index 257e72b35..c19eb6a74 100644 --- a/tests/ext/workflow/test_workflow_client.py +++ b/tests/ext/workflow/test_workflow_client.py @@ -51,6 +51,10 @@ def details(self): class FakeTaskHubGrpcClient: def __init__(self): self.last_scheduled_workflow_name = None + self.last_app_id = None + + def _record_router(self, app_id): + self.last_app_id = app_id def schedule_new_orchestration( self, @@ -59,11 +63,14 @@ def schedule_new_orchestration( instance_id, start_at, reuse_id_policy: Union[client.WorkflowIdReusePolicy, None] = None, + app_id=None, ): self.last_scheduled_workflow_name = workflow + self._record_router(app_id) return mock_schedule_result - def get_orchestration_state(self, instance_id, fetch_payloads): + def get_orchestration_state(self, instance_id, fetch_payloads, app_id=None): + self._record_router(app_id) if wf_status == 'not-found': raise SimulatedRpcError(code='UNKNOWN', details='no such instance exists') elif wf_status == 'found': @@ -73,31 +80,48 @@ def get_orchestration_state(self, instance_id, fetch_payloads): else: raise SimulatedRpcError(code='UNKNOWN', details='unknown error') - def wait_for_orchestration_start(self, instance_id, fetch_payloads, timeout): + def wait_for_orchestration_start(self, instance_id, fetch_payloads, timeout, app_id=None): + self._record_router(app_id) return self._inner_get_orchestration_state(instance_id, client.OrchestrationStatus.RUNNING) - def wait_for_orchestration_completion(self, instance_id, fetch_payloads, timeout): + def wait_for_orchestration_completion(self, instance_id, fetch_payloads, timeout, app_id=None): + self._record_router(app_id) return self._inner_get_orchestration_state( instance_id, client.OrchestrationStatus.COMPLETED ) def raise_orchestration_event( - self, instance_id: str, event_name: str, *, data: Union[Any, None] = None + self, + instance_id: str, + event_name: str, + *, + data: Union[Any, None] = None, + app_id=None, ): + self._record_router(app_id) return mock_raise_event_result def terminate_orchestration( - self, instance_id: str, *, output: Union[Any, None] = None, recursive: bool = True + self, + instance_id: str, + *, + output: Union[Any, None] = None, + recursive: bool = True, + app_id=None, ): + self._record_router(app_id) return mock_terminate_result - def suspend_orchestration(self, instance_id: str): + def suspend_orchestration(self, instance_id: str, *, app_id=None): + self._record_router(app_id) return mock_suspend_result - def resume_orchestration(self, instance_id: str): + def resume_orchestration(self, instance_id: str, *, app_id=None): + self._record_router(app_id) return mock_resume_result - def purge_orchestration(self, instance_id: str, recursive: bool = True): + def purge_orchestration(self, instance_id: str, recursive: bool = True, *, app_id=None): + self._record_router(app_id) return mock_purge_result def _inner_get_orchestration_state(self, instance_id, state: client.OrchestrationStatus): @@ -289,3 +313,60 @@ def test_client_functions(self): assert actual_purge_result == mock_purge_result actual_purge_result = wfClient.purge_workflow(instance_id=mock_instance_id) assert actual_purge_result == mock_purge_result + + +class WorkflowClientCrossAppTest(unittest.TestCase): + """Verifies app_id is forwarded to the underlying task hub client.""" + + target_app_id = 'appB' + + def _assert_forwarded(self, fake_client): + assert fake_client.last_app_id == self.target_app_id + + def test_cross_app_kwargs_are_forwarded(self): + fake_client = FakeTaskHubGrpcClient() + with mock.patch( + 'dapr.ext.workflow._durabletask.client.TaskHubGrpcClient', return_value=fake_client + ): + wfClient = DaprWorkflowClient() + routing = {'app_id': self.target_app_id} + + wfClient.schedule_new_workflow(workflow='my_registered_workflow', **routing) + self._assert_forwarded(fake_client) + + global wf_status + wf_status = 'found' + wfClient.get_workflow_state(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + wfClient.wait_for_workflow_start(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + wfClient.wait_for_workflow_completion(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + wfClient.raise_workflow_event( + instance_id=mock_instance_id, event_name='test_event', **routing + ) + self._assert_forwarded(fake_client) + + wfClient.terminate_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + wfClient.pause_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + wfClient.resume_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + wfClient.purge_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + def test_cross_app_kwargs_default_to_none(self): + fake_client = FakeTaskHubGrpcClient() + with mock.patch( + 'dapr.ext.workflow._durabletask.client.TaskHubGrpcClient', return_value=fake_client + ): + wfClient = DaprWorkflowClient() + wfClient.terminate_workflow(instance_id=mock_instance_id) + assert fake_client.last_app_id is None diff --git a/tests/ext/workflow/test_workflow_client_aio.py b/tests/ext/workflow/test_workflow_client_aio.py index 6bdf2d5be..b0e50ba45 100644 --- a/tests/ext/workflow/test_workflow_client_aio.py +++ b/tests/ext/workflow/test_workflow_client_aio.py @@ -51,6 +51,10 @@ def details(self): class FakeAsyncTaskHubGrpcClient: def __init__(self): self.last_scheduled_workflow_name = None + self.last_app_id = None + + def _record_router(self, app_id): + self.last_app_id = app_id async def schedule_new_orchestration( self, @@ -60,11 +64,14 @@ async def schedule_new_orchestration( instance_id, start_at, reuse_id_policy: Union[client.WorkflowIdReusePolicy, None] = None, + app_id=None, ): self.last_scheduled_workflow_name = workflow + self._record_router(app_id) return mock_schedule_result - async def get_orchestration_state(self, instance_id, *, fetch_payloads): + async def get_orchestration_state(self, instance_id, *, fetch_payloads, app_id=None): + self._record_router(app_id) if wf_status == 'not-found': raise SimulatedAioRpcError(code='UNKNOWN', details='no such instance exists') elif wf_status == 'found': @@ -74,31 +81,52 @@ async def get_orchestration_state(self, instance_id, *, fetch_payloads): else: raise SimulatedAioRpcError(code='UNKNOWN', details='unknown error') - async def wait_for_orchestration_start(self, instance_id, *, fetch_payloads, timeout): + async def wait_for_orchestration_start( + self, instance_id, *, fetch_payloads, timeout, app_id=None + ): + self._record_router(app_id) return self._inner_get_orchestration_state(instance_id, client.OrchestrationStatus.RUNNING) - async def wait_for_orchestration_completion(self, instance_id, *, fetch_payloads, timeout): + async def wait_for_orchestration_completion( + self, instance_id, *, fetch_payloads, timeout, app_id=None + ): + self._record_router(app_id) return self._inner_get_orchestration_state( instance_id, client.OrchestrationStatus.COMPLETED ) async def raise_orchestration_event( - self, instance_id: str, event_name: str, *, data: Union[Any, None] = None + self, + instance_id: str, + event_name: str, + *, + data: Union[Any, None] = None, + app_id=None, ): + self._record_router(app_id) return mock_raise_event_result async def terminate_orchestration( - self, instance_id: str, *, output: Union[Any, None] = None, recursive: bool = True + self, + instance_id: str, + *, + output: Union[Any, None] = None, + recursive: bool = True, + app_id=None, ): + self._record_router(app_id) return mock_terminate_result - async def suspend_orchestration(self, instance_id: str): + async def suspend_orchestration(self, instance_id: str, *, app_id=None): + self._record_router(app_id) return mock_suspend_result - async def resume_orchestration(self, instance_id: str): + async def resume_orchestration(self, instance_id: str, *, app_id=None): + self._record_router(app_id) return mock_resume_result - async def purge_orchestration(self, instance_id: str, recursive: bool = True): + async def purge_orchestration(self, instance_id: str, recursive: bool = True, *, app_id=None): + self._record_router(app_id) return mock_purge_result def _inner_get_orchestration_state(self, instance_id, state: client.OrchestrationStatus): @@ -295,3 +323,62 @@ async def test_client_functions(self): assert actual_purge_result == mock_purge_result actual_purge_result = await wfClient.purge_workflow(instance_id=mock_instance_id) assert actual_purge_result == mock_purge_result + + +class WorkflowClientAioCrossAppTest(unittest.IsolatedAsyncioTestCase): + """Verifies app_id is forwarded to the underlying async task hub client.""" + + target_app_id = 'appB' + + def _assert_forwarded(self, fake_client): + assert fake_client.last_app_id == self.target_app_id + + async def test_cross_app_kwargs_are_forwarded(self): + fake_client = FakeAsyncTaskHubGrpcClient() + with mock.patch( + 'dapr.ext.workflow._durabletask.aio.client.AsyncTaskHubGrpcClient', + return_value=fake_client, + ): + wfClient = DaprWorkflowClient() + routing = {'app_id': self.target_app_id} + + await wfClient.schedule_new_workflow(workflow='my_registered_workflow', **routing) + self._assert_forwarded(fake_client) + + global wf_status + wf_status = 'found' + await wfClient.get_workflow_state(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + await wfClient.wait_for_workflow_start(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + await wfClient.wait_for_workflow_completion(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + await wfClient.raise_workflow_event( + instance_id=mock_instance_id, event_name='test_event', **routing + ) + self._assert_forwarded(fake_client) + + await wfClient.terminate_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + await wfClient.pause_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + await wfClient.resume_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + await wfClient.purge_workflow(instance_id=mock_instance_id, **routing) + self._assert_forwarded(fake_client) + + async def test_cross_app_kwargs_default_to_none(self): + fake_client = FakeAsyncTaskHubGrpcClient() + with mock.patch( + 'dapr.ext.workflow._durabletask.aio.client.AsyncTaskHubGrpcClient', + return_value=fake_client, + ): + wfClient = DaprWorkflowClient() + await wfClient.terminate_workflow(instance_id=mock_instance_id) + assert fake_client.last_app_id is None diff --git a/tests/integration/apps/workflow_host.py b/tests/integration/apps/workflow_host.py new file mode 100644 index 000000000..57fa495db --- /dev/null +++ b/tests/integration/apps/workflow_host.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +""" +Copyright 2026 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Workflow host for cross-app integration tests. + +Registers a workflow that blocks on an external event so that every +client-level operation (get, pause, resume, raise event, terminate, purge) is +observable against a running instance. The runtime dials out to its sidecar +over gRPC, so unlike the actor and pubsub hosts this app serves no app channel +and daprd is started without an --app-port. +""" + +import signal +import threading +from typing import Any + +from dapr.ext.workflow import DaprWorkflowContext, WorkflowRuntime + +WORKFLOW_NAME = 'CrossAppWaitForEvent' +EVENT_NAME = 'Finish' + + +def wait_for_event_workflow(ctx: DaprWorkflowContext, wf_input: Any) -> Any: + """Blocks until EVENT_NAME arrives, then returns its payload.""" + payload = yield ctx.wait_for_external_event(EVENT_NAME) + return payload + + +def main() -> None: + runtime = WorkflowRuntime() + runtime.register_workflow(wait_for_event_workflow, name=WORKFLOW_NAME) + runtime.start() + + # The test drives everything through the sidecar, so this process just has + # to stay alive until it is torn down with the sidecar's process group. + stop = threading.Event() + signal.signal(signal.SIGTERM, lambda *_: stop.set()) + signal.signal(signal.SIGINT, lambda *_: stop.set()) + try: + stop.wait() + finally: + runtime.shutdown() + + +if __name__ == '__main__': + main() diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 3ea3c7eb1..28e790be2 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -109,9 +109,12 @@ def start_sidecar( self.clients.append(client) # /healthz/outbound (polled by DaprClient) only checks sidecar-side - # readiness. When we launched an app alongside the sidecar, also wait - # for /v1.0/healthz so invoke_method et al. don't race the app's server. - if app_cmd is not None: + # readiness. When the app serves an app channel, also wait for + # /v1.0/healthz so invoke_method et al. don't race the app's server. + # Keyed on app_port rather than app_cmd because some apps (workflow + # workers) dial out to the sidecar instead of listening, so they have + # no app channel for /v1.0/healthz to probe. + if app_port is not None: _wait_for_app_health(http_port) return client diff --git a/tests/integration/test_workflow_cross_app.py b/tests/integration/test_workflow_cross_app.py new file mode 100644 index 000000000..47a5710e6 --- /dev/null +++ b/tests/integration/test_workflow_cross_app.py @@ -0,0 +1,170 @@ +# -*- coding: utf-8 -*- + +""" +Copyright 2026 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +End-to-end tests for cross-app workflow client operations. + +Two sidecars are started: a host app that registers the workflow, and a caller +app that registers nothing. Every operation is issued from the caller's +DaprWorkflowClient with app_id pointing at the host, proving the target app ID +travels on the wire and the runtime routes to the owning app. + +Requires a daprd that supports cross-app workflow operations; against an older +runtime the app_id is ignored and the caller would act on its own app. +""" + +import time + +import pytest + +from dapr.ext.workflow import DaprWorkflowClient +from tests.integration.apps.workflow_host import EVENT_NAME, WORKFLOW_NAME + +pytestmark = pytest.mark.dapr_head + +HOST_APP_ID = 'wf-cross-app-host' +HOST_GRPC_PORT = 13541 +HOST_HTTP_PORT = 3541 +HOST_INTERNAL_GRPC_PORT = 13542 +HOST_METRICS_PORT = 9141 + +CALLER_APP_ID = 'wf-cross-app-caller' +CALLER_GRPC_PORT = 13551 +CALLER_HTTP_PORT = 3551 +CALLER_INTERNAL_GRPC_PORT = 13552 +CALLER_METRICS_PORT = 9151 + +WORKFLOW_READY_TIMEOUT = 30 +STATUS_TIMEOUT = 30 + + +@pytest.fixture(scope='module', autouse=True) +def sidecars(dapr_env, apps_dir): + """Starts the workflow host app and a caller app with its own sidecar.""" + dapr_env.start_sidecar( + app_id=HOST_APP_ID, + grpc_port=HOST_GRPC_PORT, + http_port=HOST_HTTP_PORT, + internal_grpc_port=HOST_INTERNAL_GRPC_PORT, + metrics_port=HOST_METRICS_PORT, + app_cmd=f'python3 {apps_dir / "workflow_host.py"}', + ) + dapr_env.start_sidecar( + app_id=CALLER_APP_ID, + grpc_port=CALLER_GRPC_PORT, + http_port=CALLER_HTTP_PORT, + internal_grpc_port=CALLER_INTERNAL_GRPC_PORT, + metrics_port=CALLER_METRICS_PORT, + ) + + +@pytest.fixture(scope='module') +def caller_client(): + """A workflow client bound to the caller sidecar, which hosts no workflows.""" + client = DaprWorkflowClient(port=str(CALLER_GRPC_PORT)) + try: + yield client + finally: + client.close() + + +@pytest.fixture(scope='module') +def host_client(): + """A workflow client bound to the host sidecar, used only to corroborate state.""" + client = DaprWorkflowClient(port=str(HOST_GRPC_PORT)) + try: + yield client + finally: + client.close() + + +def _schedule_on_host(caller_client: DaprWorkflowClient) -> str: + """Schedules the host's workflow from the caller and waits for it to run. + + The host worker registers its workflow asynchronously after its sidecar + reports ready, so scheduling is retried until the host has it. + """ + deadline = time.monotonic() + WORKFLOW_READY_TIMEOUT + last_error: Exception | None = None + while time.monotonic() < deadline: + try: + instance_id = caller_client.schedule_new_workflow( + workflow=WORKFLOW_NAME, app_id=HOST_APP_ID + ) + state = caller_client.wait_for_workflow_start( + instance_id, app_id=HOST_APP_ID, timeout_in_seconds=10 + ) + if state is not None: + return instance_id + except Exception as exc: # noqa: BLE001 - retried until the host is up + last_error = exc + time.sleep(0.5) + raise AssertionError(f'host app never accepted a cross-app schedule: {last_error}') + + +def _wait_for_status(client: DaprWorkflowClient, instance_id: str, expected: str) -> None: + deadline = time.monotonic() + STATUS_TIMEOUT + seen = None + while time.monotonic() < deadline: + state = client.get_workflow_state(instance_id, app_id=HOST_APP_ID) + seen = None if state is None else state.runtime_status.name + if seen == expected: + return + time.sleep(0.2) + raise AssertionError(f'expected status {expected}, last saw {seen}') + + +def test_cross_app_schedule_targets_the_host_app(caller_client, host_client): + """A workflow scheduled with app_id runs on the host, not on the caller.""" + instance_id = _schedule_on_host(caller_client) + + hosted = host_client.get_workflow_state(instance_id) + assert hosted is not None + assert hosted.name == WORKFLOW_NAME + + local_to_caller = caller_client.get_workflow_state(instance_id) + assert local_to_caller is None + + +def test_cross_app_pause_and_resume(caller_client): + """Pause and resume drive the remote instance through SUSPENDED and back.""" + instance_id = _schedule_on_host(caller_client) + + caller_client.pause_workflow(instance_id, app_id=HOST_APP_ID) + _wait_for_status(caller_client, instance_id, 'SUSPENDED') + + caller_client.resume_workflow(instance_id, app_id=HOST_APP_ID) + _wait_for_status(caller_client, instance_id, 'RUNNING') + + +def test_cross_app_raise_event_completes_and_purge_removes(caller_client, host_client): + """Raising the awaited event completes the remote workflow, then purge deletes it.""" + instance_id = _schedule_on_host(caller_client) + + caller_client.raise_workflow_event(instance_id, EVENT_NAME, data='finished', app_id=HOST_APP_ID) + state = caller_client.wait_for_workflow_completion( + instance_id, app_id=HOST_APP_ID, timeout_in_seconds=STATUS_TIMEOUT + ) + assert state is not None + assert state.runtime_status.name == 'COMPLETED' + + caller_client.purge_workflow(instance_id, app_id=HOST_APP_ID) + assert host_client.get_workflow_state(instance_id) is None + + +def test_cross_app_terminate(caller_client): + """Terminate stops the remote instance.""" + instance_id = _schedule_on_host(caller_client) + + caller_client.terminate_workflow(instance_id, app_id=HOST_APP_ID) + _wait_for_status(caller_client, instance_id, 'TERMINATED') diff --git a/tools/regen_durabletask_protos.sh b/tools/regen_durabletask_protos.sh index 4b9120f11..e1b8be4e0 100755 --- a/tools/regen_durabletask_protos.sh +++ b/tools/regen_durabletask_protos.sh @@ -15,7 +15,8 @@ # Regenerate Python protobuf/gRPC stubs for the vendored durabletask package. # -# Proto source files are fetched from the durabletask-protobuf repository. +# Proto source files are fetched from the durabletask-protobuf repository, or +# taken from a local checkout when DURABLETASK_PROTOBUF_DIR is set. # Generated output goes to dapr/ext/workflow/_durabletask/internal/ # # Prerequisites: uv sync --all-extras --group dev @@ -23,43 +24,65 @@ # Usage: # ./tools/regen_durabletask_protos.sh # DURABLETASK_PROTOBUF_BRANCH=v1.2.3 ./tools/regen_durabletask_protos.sh +# DURABLETASK_PROTOBUF_DIR=/path/to/durabletask-protobuf ./tools/regen_durabletask_protos.sh set -euo pipefail DURABLETASK_PROTOBUF_BRANCH=${DURABLETASK_PROTOBUF_BRANCH:-main} +DURABLETASK_PROTOBUF_DIR=${DURABLETASK_PROTOBUF_DIR:-} +proto_source_commit="" REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" OUTPUT_DIR="${REPO_ROOT}/dapr/ext/workflow/_durabletask/internal" PYTHON_PACKAGE="dapr.ext.workflow._durabletask.internal" -if type "curl" > /dev/null 2>&1; then - HTTP_REQUEST_CLI=curl -elif type "wget" > /dev/null 2>&1; then - HTTP_REQUEST_CLI=wget +if [ -n "$DURABLETASK_PROTOBUF_DIR" ]; then + if [ ! -d "${DURABLETASK_PROTOBUF_DIR}/protos" ]; then + echo "Error: ${DURABLETASK_PROTOBUF_DIR}/protos does not exist" + exit 1 + fi + echo "Using local durabletask-protobuf checkout at ${DURABLETASK_PROTOBUF_DIR}" + proto_dir="${DURABLETASK_PROTOBUF_DIR}/protos" + proto_source_commit="$(git -C "${DURABLETASK_PROTOBUF_DIR}" rev-parse HEAD 2>/dev/null || true)" else - echo "Either curl or wget is required" - exit 1 -fi + if type "curl" > /dev/null 2>&1; then + HTTP_REQUEST_CLI=curl + elif type "wget" > /dev/null 2>&1; then + HTTP_REQUEST_CLI=wget + else + echo "Either curl or wget is required" + exit 1 + fi -tmp="$(mktemp -d)" -trap 'rm -rf "$tmp"' EXIT + tmp="$(mktemp -d)" + trap 'rm -rf "$tmp"' EXIT -url="https://github.com/dapr/durabletask-protobuf/archive/refs/heads/${DURABLETASK_PROTOBUF_BRANCH}.tar.gz" + url="https://github.com/dapr/durabletask-protobuf/archive/refs/heads/${DURABLETASK_PROTOBUF_BRANCH}.tar.gz" -echo "Downloading durabletask-protobuf from ${url}..." -pushd "$tmp" > /dev/null -if [ "$HTTP_REQUEST_CLI" == "curl" ]; then - curl -SsL "$url" -o - | tar --strip-components=1 -xzf - -else - wget -q -O - "$url" | tar --strip-components=1 -xzf - + echo "Downloading durabletask-protobuf from ${url}..." + pushd "$tmp" > /dev/null + if [ "$HTTP_REQUEST_CLI" == "curl" ]; then + curl -SsL "$url" -o - | tar --strip-components=1 -xzf - + else + wget -q -O - "$url" | tar --strip-components=1 -xzf - + fi + popd > /dev/null + + proto_dir="${tmp}/protos" + + # The tarball carries no git metadata, so resolve the branch head via the API. + api_url="https://api.github.com/repos/dapr/durabletask-protobuf/commits/${DURABLETASK_PROTOBUF_BRANCH}" + if [ "$HTTP_REQUEST_CLI" == "curl" ]; then + proto_source_commit="$(curl -SsL -H 'Accept: application/vnd.github.sha' "$api_url" 2>/dev/null || true)" + else + proto_source_commit="$(wget -q -O - --header='Accept: application/vnd.github.sha' "$api_url" 2>/dev/null || true)" + fi fi -popd > /dev/null # The .proto files live under protos/ in durabletask-protobuf and use bare # imports like: import "orchestration.proto" # # We use the protos directory as the single --proto_path so that bare imports # resolve correctly. Generated files land directly in the output directory. -proto_dir="${tmp}/protos" proto_files=() while IFS= read -r -d '' file; do @@ -129,5 +152,15 @@ for f in "${OUTPUT_DIR}"/*_pb2.py; do fi done +# Record which durabletask-protobuf commit produced these stubs. Without this +# the file is edited by hand and silently drifts from the generated code. +if [ -n "$proto_source_commit" ]; then + echo "$proto_source_commit" > "${OUTPUT_DIR}/PROTO_SOURCE_COMMIT_HASH" + echo "Recorded source commit ${proto_source_commit}" +else + echo "Warning: could not resolve the durabletask-protobuf commit;" \ + "update ${OUTPUT_DIR}/PROTO_SOURCE_COMMIT_HASH by hand" +fi + echo -e "\nDurableTask protobuf/gRPC stubs regenerated successfully!" echo "Output: ${OUTPUT_DIR}" From 6732be77b0ac8e8fd0014a6d710398237f4281aa Mon Sep 17 00:00:00 2001 From: joshvanl Date: Wed, 9 Sep 2026 15:59:12 -0300 Subject: [PATCH 2/2] Review comments Signed-off-by: joshvanl --- .../internal/orchestrator_service_pb2.pyi | 6 +++--- .../durabletask/test_orchestration_executor.py | 4 ++-- tools/regen_durabletask_protos.sh | 13 +++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi b/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi index f0064bd6b..40cc431b7 100644 --- a/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi +++ b/dapr/ext/workflow/_durabletask/internal/orchestrator_service_pb2.pyi @@ -659,9 +659,9 @@ class PurgeInstancesRequest(_message.Message): @_builtins.property def router(self) -> _orchestration_pb2.TaskRouter: """router optionally routes this operation to the workflow instance owned - by another app. The purge is delegated to the target app, which honours - the caller's recursive flag. sourceAppID is stamped by the sidecar, not - the client. + by another app. Cross-app purges are delegated to the target app in + full, so they are always recursive on the remote side. sourceAppID is + stamped by the sidecar, not the client. """ def __init__( diff --git a/tests/ext/workflow/durabletask/test_orchestration_executor.py b/tests/ext/workflow/durabletask/test_orchestration_executor.py index 551d03abb..d6f164fd4 100644 --- a/tests/ext/workflow/durabletask/test_orchestration_executor.py +++ b/tests/ext/workflow/durabletask/test_orchestration_executor.py @@ -246,7 +246,7 @@ def orchestrator(ctx: task.OrchestrationContext, orchestrator_input): def test_schedule_activity_actions_router_without_app_id(): - """Tests that the workflow action carries correct router fields when app_id is specified""" + """Tests that the workflow action carries no target app ID when app_id is not specified""" def dummy_activity(ctx, _): pass @@ -767,7 +767,7 @@ def orchestrator(ctx: task.OrchestrationContext, _): def test_create_sub_orchestration_actions_router_without_app_id(): - """Tests that the workflow action carries correct router fields when app_id is specified""" + """Tests that the workflow action carries no target app ID when app_id is not specified""" def suborchestrator(ctx: task.OrchestrationContext, _): pass diff --git a/tools/regen_durabletask_protos.sh b/tools/regen_durabletask_protos.sh index e1b8be4e0..20b048eb1 100755 --- a/tools/regen_durabletask_protos.sh +++ b/tools/regen_durabletask_protos.sh @@ -42,6 +42,19 @@ if [ -n "$DURABLETASK_PROTOBUF_DIR" ]; then fi echo "Using local durabletask-protobuf checkout at ${DURABLETASK_PROTOBUF_DIR}" proto_dir="${DURABLETASK_PROTOBUF_DIR}/protos" + + # The recorded commit is only meaningful if the protos it names are the ones + # actually fed to protoc. Uncommitted or untracked proto changes would be + # baked into the stubs while PROTO_SOURCE_COMMIT_HASH pointed at HEAD, so the + # provenance would be a lie. Refuse instead: commit the proto change (or push + # it upstream) and rerun. + if [ -n "$(git -C "${DURABLETASK_PROTOBUF_DIR}" status --porcelain -- protos 2>/dev/null)" ]; then + echo "Error: ${DURABLETASK_PROTOBUF_DIR}/protos has uncommitted or untracked changes." + echo "The generated stubs would not match the commit recorded in PROTO_SOURCE_COMMIT_HASH." + git -C "${DURABLETASK_PROTOBUF_DIR}" status --short -- protos + exit 1 + fi + proto_source_commit="$(git -C "${DURABLETASK_PROTOBUF_DIR}" rev-parse HEAD 2>/dev/null || true)" else if type "curl" > /dev/null 2>&1; then