Skip to content

feat(trigger-service): add WorkflowServiceClient Dapr adapter (TS-IMPL-013)#666

Merged
toddysm merged 2 commits into
mainfrom
ts-impl-013-wf-client
Jun 5, 2026
Merged

feat(trigger-service): add WorkflowServiceClient Dapr adapter (TS-IMPL-013)#666
toddysm merged 2 commits into
mainfrom
ts-impl-013-wf-client

Conversation

@toddysm
Copy link
Copy Markdown
Owner

@toddysm toddysm commented Jun 5, 2026

Summary

Implements TS-IMPL-013 — the WorkflowServiceClient Dapr service-invocation
adapter the dispatcher (TS-IMPL-014) uses to drive the Workflow Service's two
inbound Internal RPCs.

Closes #643

What's included

  • custos_trigger/clients/workflow.py — outbound client over the local Dapr
    sidecar (http://{host}:{port}/v1.0/invoke/{appId}/method/{method}), mirroring
    the Workflow Service's own _dapr_invoke precedent:
    • start_run(...)POST /internal/runs:start, returns RunRef.
    • raise_external_event(run_id, step_id, ...)
      POST /internal/runs/{runId}/steps/{stepId}:raiseEvent (202, empty body).
    • Request bodies (StartRunRequest, RaiseExternalEventRequest) match the WF
      InternalStartRunRequest / RaiseExternalEventRequest camelCase wire
      contracts; idempotencyKey is sent in the body and as an
      Idempotency-Key header when present.
    • Error taxonomy: transport failures and 408/429/5xx raise a retryable
      WorkflowClientError; permanent 4xx and undecodable 2xx bodies raise a
      non-retryable one — so the dispatcher can backoff/retry vs. dead-letter.
    • DaprEndpoint + build_invoke_url + read_dapr_endpoint (host/port from
      DAPR_HTTP_HOST / DAPR_HTTP_PORT, app id supplied by the caller).
    • NoopWorkflowServiceClient and recording FakeWorkflowServiceClient doubles.
  • pyproject.toml — promotes httpx from a dev-only to a runtime dependency
    (the client uses it at runtime).
  • tests/test_workflow_client.py — async coverage of URL/endpoint helpers,
    start/raise success, idempotency header on/off, retryable 5xx/429, permanent
    4xx, transport + decode errors, and both doubles.

Acceptance

  • Request bodies match the WF InternalStartRunRequest / RaiseExternalEventRequest schemas.
  • Transient 5xx surface a retryable error; Fake records calls; 100% adapter coverage.
  • ruff / ruff format / mypy clean; pytest ≥90% (99.9% total).

Add the outbound Dapr service-invocation client the dispatcher uses to drive
the Workflow Service Internal RPCs: start_run -> POST /internal/runs:start and
raise_external_event -> POST /internal/runs/{runId}/steps/{stepId}:raiseEvent.
Request bodies mirror the WF InternalStartRunRequest/RaiseExternalEventRequest
wire contracts; idempotencyKey is propagated in the body and Idempotency-Key
header. Transport failures and 408/429/5xx raise a retryable error; permanent
4xx and undecodable bodies raise non-retryable. Adds Noop and Fake doubles and
promotes httpx to a runtime dependency.

Closes #643
Copilot AI review requested due to automatic review settings June 5, 2026 04:38
@toddysm toddysm added type:implementation Implementation work item phase:implementation Implementation phase component:trigger-service Trigger Service component labels Jun 5, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the Trigger Service’s outbound WorkflowServiceClient implementation for invoking Workflow Service internal RPCs via the local Dapr sidecar, plus test coverage and dependency updates to support runtime httpx usage.

Changes:

  • Introduces DaprWorkflowServiceClient with wire models and retryable/permanent error taxonomy for start_run and raise_external_event.
  • Adds unit tests covering endpoint/url helpers, success paths, error mapping, and doubles (Noop/Fake).
  • Promotes httpx to a runtime dependency and marks TS-IMPL-013 complete in the trigger-service design TODOs.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/services/trigger-service/src/custos_trigger/clients/workflow.py Adds the Dapr service-invocation adapter, wire models, error taxonomy, and doubles for Workflow Service RPCs.
src/services/trigger-service/tests/test_workflow_client.py Adds async unit tests for URL/env helpers, success/error behavior, and client doubles.
src/services/trigger-service/src/custos_trigger/clients/init.py Introduces the clients package and re-exports the workflow client surface.
src/services/trigger-service/pyproject.toml Moves httpx from dev-only to runtime dependency.
design/components/trigger-service/todos.md Marks TS-IMPL-013 as completed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/services/trigger-service/src/custos_trigger/clients/workflow.py
Comment thread src/services/trigger-service/src/custos_trigger/clients/workflow.py
Reject empty host/app_id and non-positive port in DaprEndpoint, and reject
empty/slash-only method paths in build_invoke_url, mirroring the workflow-
service _dapr_invoke precedent and failing fast on unusable endpoints.
@toddysm toddysm merged commit 45a6580 into main Jun 5, 2026
30 checks passed
@toddysm toddysm deleted the ts-impl-013-wf-client branch June 5, 2026 04:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component:trigger-service Trigger Service component phase:implementation Implementation phase type:implementation Implementation work item

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants