Files
Naomi Most c8e63df574 feat(rest): add task signal endpoints (#1205)
* feat(rest): add task signal endpoints

Adds the task signal endpoints the Go SDK / CLI already call but OSS never
implemented (conductor-oss/conductor#1197):

  POST /api/tasks/{workflowId}/{status}/signal        (async)
  POST /api/tasks/{workflowId}/{status}/signal/sync   (sync, returns SignalResponse)

Before this, the SDK's SignalAsync hit POST /tasks/{wfId}/{status}/signal, which
had no matching route, so Spring fell through to the all-variable update route
/{workflowId}/{taskRefName}/{status} and tried to coerce the literal "signal"
into TaskResult.Status -> MethodArgumentTypeMismatchException. Adding the literal
/signal segment makes that pattern more specific, so it now wins; a MockMvc
routing test (with PathPatternParser, mirroring production) locks this in.

"Signal" finds the first non-terminal WAIT task in the workflow (descending into
running sub-workflows) and applies the given status + output to it, via the new
TaskService.signalTask. The sync variant then waits for the workflow to settle
into its next blocking/terminal state and renders a SignalResponse per the
returnStrategy, reusing the same poll-to-response logic as executeWorkflow --
extracted into WorkflowSignalResponder so both controllers share it.

Tests: TaskServiceTest (signalTask found / not-found), TaskResourceTest (async,
sync, not-found, route resolution). Full conductor-rest suite green.

* fix(signal): add signalTimeout field and E2E Groovy integration tests

Two issues raised in PR #1205 review:

1. `SignalResponse` was missing the `signalTimeout` boolean that Orkes sets
   when the sync-signal poll times out. Without it a timed-out response looks
   identical to a successful one. Added `signalTimeout` to `SignalResponse`
   (absorbed by `WorkflowRun` and `TaskRun` via inheritance), propagated it
   through `NotificationResult.toResponse()`, and set it to `true` in
   `WorkflowSignalResponder`'s timeout fallback path.

2. Added `SignalTaskSpec` to the test-harness — a Spring Boot integration test
   backed by a real Redis testcontainer that exercises `TaskService.signalTask()`
   without any mocking: direct-WAIT-task signal, signal-with-no-blocker,
   signal-on-nonexistent-workflow, and sub-workflow descent.

* test(signal): remove mocked signal tests — covered by SignalTaskSpec E2E

* fix(test): SignalTaskSpec — expect NotFoundException for missing workflow

ExecutionDAOFacade.getWorkflow() throws NotFoundException for unknown IDs
(does not return null). The test was asserting null — corrected to thrown().

The e2e WorkflowRerunTests failure in the same CI run is pre-existing and
unrelated to signal changes (it was already failing on the prior commit).

* test(e2e): HTTP-level signal endpoint tests (async + sync)

* fix: spotless formatting violations in SignalTaskTest
2026-07-17 16:29:17 -07:00
..
2026-05-28 07:45:16 -07:00