Skip to content

Commit e492db2

Browse files
committed
feat: Implement signal_workflow method
Signed-off-by: Tim Li <ltim@uber.com>
1 parent f91c925 commit e492db2

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

cadence/client.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from grpc.aio import Channel, ClientInterceptor, secure_channel, insecure_channel
1616
from cadence.api.v1.service_workflow_pb2_grpc import WorkflowAPIStub
1717
from cadence.api.v1.service_workflow_pb2 import (
18+
SignalWorkflowExecutionRequest,
1819
StartWorkflowExecutionRequest,
1920
StartWorkflowExecutionResponse,
2021
)
@@ -229,6 +230,51 @@ async def start_workflow(
229230
except Exception:
230231
raise
231232

233+
async def signal_workflow(
234+
self,
235+
workflow_id: str,
236+
run_id: str,
237+
signal_name: str,
238+
signal_input: Any = None,
239+
) -> None:
240+
"""
241+
Send a signal to a running workflow execution.
242+
243+
Args:
244+
workflow_id: The workflow ID
245+
run_id: The run ID (can be empty string to signal current run)
246+
signal_name: Name of the signal
247+
signal_input: Input data for the signal
248+
249+
Raises:
250+
ValueError: If signal encoding fails
251+
Exception: If the gRPC call fails
252+
"""
253+
signal_payload = None
254+
if signal_input is not None:
255+
try:
256+
signal_payload = await self.data_converter.to_data(signal_input)
257+
except Exception as e:
258+
raise ValueError(f"Failed to encode signal input: {e}")
259+
260+
workflow_execution = WorkflowExecution()
261+
workflow_execution.workflow_id = workflow_id
262+
if run_id:
263+
workflow_execution.run_id = run_id
264+
265+
signal_request = SignalWorkflowExecutionRequest(
266+
domain=self.domain,
267+
workflow_execution=workflow_execution,
268+
identity=self.identity,
269+
request_id=str(uuid.uuid4()),
270+
signal_name=signal_name,
271+
)
272+
273+
if signal_payload:
274+
signal_request.signal_input.CopyFrom(signal_payload)
275+
276+
await self.workflow_stub.SignalWorkflowExecution(signal_request)
277+
232278

233279
def _validate_and_copy_defaults(options: ClientOptions) -> ClientOptions:
234280
if "target" not in options:

tests/integration_tests/test_client.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,52 @@ async def test_workflow_stub_start_and_describe(helper: CadenceHelper):
136136
assert task_timeout_seconds == task_timeout.total_seconds(), (
137137
f"task_start_to_close_timeout mismatch: expected {task_timeout.total_seconds()}s, got {task_timeout_seconds}s"
138138
)
139+
140+
141+
@pytest.mark.usefixtures("helper")
142+
async def test_signal_workflow(helper: CadenceHelper):
143+
"""Test signal_workflow method.
144+
145+
This integration test verifies:
146+
1. Starting a workflow execution
147+
2. Sending a signal to the running workflow
148+
3. Signal is accepted (no errors thrown)
149+
"""
150+
async with helper.client() as client:
151+
workflow_type = "test-workflow-signal"
152+
task_list_name = "test-task-list-signal"
153+
workflow_id = "test-workflow-signal-789"
154+
execution_timeout = timedelta(minutes=5)
155+
signal_name = "test-signal"
156+
signal_input = {"action": "update", "value": 42}
157+
158+
execution = await client.start_workflow(
159+
workflow_type,
160+
task_list=task_list_name,
161+
execution_start_to_close_timeout=execution_timeout,
162+
workflow_id=workflow_id,
163+
)
164+
165+
await client.signal_workflow(
166+
workflow_id=execution.workflow_id,
167+
run_id=execution.run_id,
168+
signal_name=signal_name,
169+
signal_input=signal_input,
170+
)
171+
172+
describe_request = DescribeWorkflowExecutionRequest(
173+
domain=DOMAIN_NAME,
174+
workflow_execution=WorkflowExecution(
175+
workflow_id=execution.workflow_id,
176+
run_id=execution.run_id,
177+
),
178+
)
179+
180+
response = await client.workflow_stub.DescribeWorkflowExecution(
181+
describe_request
182+
)
183+
184+
assert (
185+
response.workflow_execution_info.workflow_execution.workflow_id
186+
== workflow_id
187+
)

0 commit comments

Comments
 (0)