Skip to main content

Choose a backing implementation

View Markdown

The contract says nothing about what runs behind an Operation. That is the handler's private decision, and it can change later without touching callers.

Picking the wrong backing is the most common source of trouble later. This step chooses one for each Operation in the approval Service.

Workflow​

Use a Workflow for more than one step, any need to wait, or any need for durable intermediate state.

The Operation starts a Workflow and completes when that Workflow returns, so the Workflow's return value is the Operation's result. Use this when the work orchestrates several Activities, needs a timer, receives messages while it runs, or must survive a Worker restart partway through.

A long-lived Workflow that accepts messages is still an ordinary Workflow. What makes it interactive is its message handlers and a Workflow Id you can predict.

Standalone Activity​

Use a Standalone Activity for one step with no waiting and no state: call an external API, run a computation, send a notification.

The Operation starts an Activity Execution with no parent Workflow and completes when the Activity returns. You get retries, timeouts, and a durable record of every attempt without a wrapper Workflow that exists only to call one Activity.

An Activity cannot receive messages or hold state, and cancellation only works if the Activity heartbeats. See Nexus Standalone Activity.

The choice for the approval Service​

OperationBackingWhy
requestApprovalWorkflowBlocks for a human decision, holds the reminder count, and accepts messages while pending
remindApproverSync messaging (Signal)A Signal to the approval started by requestApproval
submitDecisionUpdateAn Update to that same approval, because the caller needs a result back
attachApprovalContextSync messaging (Signal-with-Start)A Signal that also starts the approval if it does not exist yet
notifyRequesterStandalone ActivityOne outbound notification, no state, nothing to wait for

An Update is its own backing: the Operation completes when the Update completes, not when the Workflow returns. Signals are not a backing. They are sync messaging, which takes effect and completes the Operation during the handler call.

The caller can observe the difference. A Signal-backed Operation completes synchronously, so a Temporal caller's Event History goes straight from NexusOperationScheduled to NexusOperationCompleted. An Update-backed Operation completes through the Nexus completion callback, which adds a NexusOperationStarted event carrying the Operation token used to cancel it.

The approval has to be a Workflow. It exists for a while, has an identity, and other systems interact with it during its lifetime. An Activity cannot block for a human or receive a Signal.

The notification is the opposite: a single side effect with nothing to orchestrate. A Workflow would add an Event History and a Workflow Id for no benefit, but the notification touches the outside world and can fail, so it needs the retries an Activity provides.

Give the approval Workflow a stable Id​

Derive the approval's Workflow Id from the purchase, not a random value, so that later messages can find it. A caller that knows the item id can then reach the right Execution without the handler handing out Workflow Ids.

This also makes the start idempotent: a retried Nexus start request targets the same Workflow Id rather than starting a second approval for one purchase.

Derive it in one place so the two Operations that need it cannot drift apart:

core/src/main/java/io/temporal/samples/nexuswalkthrough/handler/ApprovalWorkflowId.java

public static String forItem(String itemId) {
return "approval-" + itemId;
}

In step 8, attachApprovalContext may start the approval before requestApproval is called. Both Operations derive the same Workflow Id from the same item id, so they agree on which Execution they mean.

RESOURCES

Next step​

Step 4: Implement the Service

The approval Workflow, the handler, the development server, and a Worker.

→