Workflow Definition
A Workflow Definition is the code that defines your Workflow.
Workflow Type
The Workflow Type is the name that maps to a Workflow Definition. It’s an identifier that makes it possible to distinguish one type of Workflow (such as order processing) from another (such as customer onboarding).
Workflow Execution, Commands, Events and Event History
A Workflow Execution is a running Workflow, which is created by combining a Workflow Definition with a request to execute it. You can execute a Workflow Definition any number of times, potentially providing different input each time. Each Workflow Execution progresses through a series of Commands and Events, which are recorded in an Event History. A Workflow Definition may be also referred to as a Workflow Function
Each Temporal Workflow Execution has exclusive access to its local state. It executes concurrently to all other Workflow Executions, and communicates with other Workflow Executions through Signals and the environment through Activities. While a single Workflow Execution has limits on size and throughput, a Temporal Application can consist of millions to billions of Workflow Executions.
Determinism in Workflow Definitions
A critical aspect of developing Workflow Definitions is ensuring that they are deterministic. Generally speaking, this means you must take care to ensure that any time your Workflow code is executed it makes the same Workflow API calls in the same sequence, given the same input.
Non Determinism during Worflow C
ode Change
To alleviate non-deterministic issues that arise from code changes, we recommend using Workflow Versioning.
Signals
In Temporal, a Signal is a way to asynchronously send data or commands to a running Workflow without restarting it or blocking the caller.
Signal can modify workflow state, Is durable and replay safe. Does not return a result (unlike a query)
Who can send a signal
In Temporal, any trusted client that can reach the Temporal service and knows the Workflow ID can send a Signal.This is the primary and recommended way
Examples:
Backend microservices
API services
BFF / Gateway services
Admin or Ops tools
A workflow can signal another workflow (child or unrelated).
Activites cannot send signal
Activities cannot send signals because Activities are not trusted, deterministic, or durable coordinators.
Only Workflows are allowed to coordinate state and communication.
Activities can be retried many times:
If an Activity sends a signal:
❌ Signal could be sent multiple times
❌ No deterministic way to prevent duplication
❌ Exactly-once guarantees break
Workflows, on the other hand:
Execute deterministically
Replay history safely
Send signals once per decision
Allowing Activities to signal would mean:
Signals could be lost
Signals could be duplicated
System state becomes inconsistent
Correct Pattern (Activity → Workflow → Signal)
Activity completes
↓
Workflow processes result
↓
Workflow sends signal to another workflow
Why external clients CAN signal but Activities cannot
External clients are not replayed or retried by Temporal, while Activities are.
Temporal only allows non-replayed actors to send signals.
External clients can signal because they are not replayed or retried by Temporal, so each signal represents a single intentional event. Activities cannot signal because they are retried and non-deterministic, which would lead to duplicate or lost signals and break Temporal’s exactly-once workflow coordination guarantees.
Mental model to remember
Coordination must come from outside Temporal or from deterministic workflow code — never from retried side-effect executors.
Activity
An Activity is:
A function registered with a Temporal Worker
Executed by worker processes
Invoked by a Workflow
Retried, timed out, and tracked by Temporal
Activity = code unit, not a service boundary
Activity and Microservice Patterns
Pattern 1: Microservice is called by an Activity
Workflow → Activity → HTTP call → Inventory Service
The microservice is a normal external system
The Activity is just a client to that service
Temporal has no awareness of that service
Pattern 2 The Activity function exists inside the microservice code. The code gets registered with Temporal.
Pattern 2 in detail
Inside one microservice you effectively have two Temporal-related contexts:
A) Activity execution context
Code runs inside a Temporal worker
Retried automatically
❌ Should not coordinate or signal
B)Client / API / Listener context
Runs as normal service code
Triggered by HTTP, Kafka, scheduler, etc.
❌ Not replayed by Temporal
✔️ Can signal workflows
✔️ Can use JPA normally
how much code from the activity gets registered with Temporal?
Temporal registers only the Activity name and signature, not the activity’s implementation code.
Temporal never stores, uploads, or understands your business logic.
When it is time to execute the activity -
A worker polling the task queue:
Sees the activity type name
Looks up the local method registered under that name
Executes your Java code
Worker reports:
Success → serialized result
Failure → exception
How does the worker invoke activity code
When your microservice starts, it does this:
Worker worker = factory.newWorker(“ORDER_TASK_QUEUE”);
worker.registerActivitiesImplementations(
new OrderActivitiesImpl()
);
2️⃣ Worker connects to Temporal service
Separately, the worker:
Opens a gRPC connection to the Temporal service
Starts polling the task queue
So it is actually Worker code opening a connection to Temporal and registering itself and then executing the Activity Function which is like a library jar for it. So I guess the Activity Function can be considered to be scope of Activity
Common Misconception
“Temporal calls my activity method directly”
❌ No.
Correct mental model:
Workflow
↓ ScheduleActivity
Temporal Service
↓ Task Queue
Worker
↓ Registry lookup
Activity Method
Temporal never knows:
Where your code lives
What language you use
How your logic works
Worker Lifecycle
Start worker
→ Poll task queue
→ Execute task
→ Report result
→ Poll again
Task Queues
Recommendation is to create one workflow queue and one activity queue per domain
ORDER-WORKFLOW-QUEUE
ORDER-ACTIVITY-QUEUE
Sending the same signal multiple times due to service replication
If an activity calls a replicated service and all instances send the same signal, the workflow will receive the signal multiple times because Temporal does not deduplicate signals. This can break business invariants. The correct design is to ensure only a single coordinator sends the signal or to make signal handling idempotent inside the workflow. Activities themselves should not send signals.
Temporal and kubernetes
Temporal is typically used with Kubernetes by running Temporal workers as stateless pods that poll task queues, while the Temporal service itself may be self-hosted in Kubernetes or provided via Temporal Cloud. Kubernetes provides horizontal scaling and fault tolerance, and Temporal ensures durable execution, retries, and coordination across pod restarts.
What can be passed in a Signal
In Temporal, a Signal can carry any data that is serializable by your Temporal SDK. A signal payload can contain: Plain objects (POJOs / DTOs), JSON-serializable structures
Use cases of signals
Human in the loop
- A workflow is waiting for a human decision that can arrive at any time.
Workflow starts
↓
Waits for approval
↓
Signal arrives → resume
External Async Event
Workflow depends on an event produced by another system.
Workflow → waits
External system → signals
Workflow → continues
Can a Worker execute both Activity and Workflow tasks?
Yes. A single worker process can poll a task queue and execute both workflows and activities — as long as both are registered on that worker.
Worker worker = factory.newWorker(“ORDER-QUEUE”);
worker.registerWorkflowImplementationTypes(OrderWorkflowImpl.class);
worker.registerActivitiesImplementations(new OrderActivitiesImpl());
factory.start();
who kicks off the workflow and specifies where its workflow task queuee should be
A Temporal client kicks off the workflow and specifies the workflow task queue.
The Temporal Server then owns everything after that.
OrderWorkflow workflow =
client.newWorkflowStub(
OrderWorkflow.class,
WorkflowOptions.newBuilder()
.setTaskQueue(“ORDER-WORKFLOW-QUEUE”)
.build()
);
workflow.start(orderId);
Activity Stub
Workflow.newActivityStub(…) is how workflow code gets a safe, deterministic handle to call Activities in Temporal.
PaymentActivities activities =
Workflow.newActivityStub(
PaymentActivities.class,
ActivityOptions.newBuilder()
.setTaskQueue(“PAYMENT-ACTIVITY-QUEUE”)
.setStartToCloseTimeout(Duration.ofSeconds(30))
.build()
);
activities.chargeCard(orderId);
This does NOT:
Call the Java method directly
Execute business logic
Make network calls