Temporal Workflow Sidecar: Keeping Orchestration Out of Your Domain
The Gotcha
Keep orchestration logic separate from your domain code by running Temporal workflows in a dedicated sidecar service.
🎯 System Scenario & Requirements
System Goal
Keep orchestration logic separate from your domain code by running Temporal workflows in a dedicated sidecar service.
Actors & Components
- Domain Layer
- Temporal Sidecar
- Infrastructure & External
- App Service
- Workflow API
- Temporal Orchestrator
- Temporal Worker
- Domain Activity
Functional Requirements
- TLDR: Keep orchestration logic separate from your domain code by running Temporal workflows in a dedicated sidecar service.
- This preserves Clean Architecture layers, simplifies unit tests, and gives you a single point for retry & monitoring.
- 🚀 When you sprinkle Temporal SDK calls ( workflow.execute , workflow.schedule ) directly inside your domain services, you violate the Dependency Rule of Clean Architecture: the inner layers now depend on an outer frame…
Constraints & Assumptions
- Constraints are derived from the rebuilt scenario stages.
⚡ Execution Stages & Decision Trace
Stage 1 — The Sidecar Solution
Create a Temporal Orchestrator Service —a thin, stateless sidecar that: 1.
Exposes a clean port (e.g., a gRPC or HTTP API) for your domain services to request workflow starts.
Deep Dive
Scenario context
Keep orchestration logic separate from your domain code by running Temporal workflows in a dedicated sidecar service. This preserves Clean Architecture layers, simplifies unit tests, and gives you a single point for retry & monitoring. 🚀
When you sprinkle Temporal SDK calls (workflow.execute, workflow.schedule) directly inside your domain services, you violate the Dependency Rule of Clean Architecture: the…
This walkthrough focuses on The Gotcha.
Before making a design choice, clarify:
- When you sprinkle Temporal SDK calls ( workflow.execute , workflow.schedule ) directly inside your domain services, you violate the Dependency Rule of Clean Architecture: the inner layers now depend on an outer framewor…
- This tight coupling makes unit testing hard (you must mock Temporal), hampers refactoring, and blurs the boundary between business logic and orchestration concerns.
Concepts in play: event-driven-architecture, design-patterns-gof, stack-and-queue-data-structures
Stage 1 — The Sidecar Solution
- Create a Temporal Orchestrator Service —a thin, stateless sidecar that: 1.
- Exposes a clean port (e.g., a gRPC or HTTP API) for your domain services to request workflow starts.
- Uses the Temporal SDK to orchestrate workflows, delegating domain work to activities that call back into your domain via ports/adapters.
- Keeps all Temporal dependencies outside the core domain layer, so the domain remains pure and testable.
Observable outcome: Keeps all Temporal dependencies outside the core domain layer, so the domain remains pure and testable.
Stage 2 — Architecture Kit Diagram
- { "version": 1, "title": "Temporal Sidecar in Clean Architecture", "description": "Shows how a sidecar orchestrates Temporal workflows while keeping domain services isolated", "view": "data-flow", "pattern": "reactive-p…
Observable outcome: { "version": 1, "title": "Temporal Sidecar in Clean Architecture", "description": "Shows how a sidecar orchestrates Temporal workflows while keeping domain services isolated", "view": "data-flow", "pattern": "reactive-p…
Stage 3 — Trade‑offs
- Pros : Clear separation, easier unit tests, single point for retry/backoff logic, independent scaling.
- Cons : Extra deployment unit, more operational overhead, latency added by inter‑service calls.
Observable outcome: - Cons : Extra deployment unit, more operational overhead, latency added by inter‑service calls.
Stage 4 — Production Tips
- Keep the sidecar stateless; let Temporal handle state.
- Use dependency injection in the sidecar to swap activity implementations for testing.
- Expose metrics (e.g., workflow counts, error rates) from the sidecar to a monitoring stack.
- Run the sidecar in the same pod as the Temporal worker if you want minimal latency, but still expose a clean port for the domain.
Observable outcome: - Run the sidecar in the same pod as the Temporal worker if you want minimal latency, but still expose a clean port for the domain.
End-to-end outcome
When you sprinkle Temporal SDK calls ( workflow.execute , workflow.schedule ) directly inside your domain services, you violate the Dependency Rule of Clean Architecture: the inner layers now depend on an outer framework.
Alternatives considered
The source focuses on one primary design. A second architecture is not compared, so no alternative is invented here.
Failure and degraded modes
The source does not isolate a separate failure mode. Limits that matter for the scenario are called out in the stage decisions above.
Key learnings
- Create a Temporal Orchestrator Service —a thin, stateless sidecar that: 1.
- { "version": 1, "title": "Temporal Sidecar in Clean Architecture", "description": "Shows how a sidecar orchestrates Temporal workflows while keeping domain services isolated", "view": "data-flow", "pattern": "reactive-p…
- Pros : Clear separation, easier unit tests, single point for retry/backoff logic, independent scaling.
- Keep the sidecar stateless; let Temporal handle state.
