MutableSideEffect value comparison behavior
Mutable Side Effects compare the existing value from History with the new function results using an equals function. If the values are equal, it returns the value without recording a new Marker Event. If the values are not equal, it records the new value with the same ID on the History.
SideEffect correct implementation example
The correct way to use SideEffect is to capture the returned EncodedValue and call Get() on it with a pointer to store the result:
```go
encodedRandom := workflow.SideEffect(ctx, func(ctx workflow.Context) interface{} {
return rand.Intn(100)
})
var random int
encodedRandom.Get(&random)
```
Go SDK SideEffect function signature and usage
Use the SideEffect function from the go.temporal.io/sdk/workflow package to execute a Side Effect directly in your Workflow. Pass it an instance of context.Context and the function to execute. The SideEffect API returns a Future, an instance of converter.EncodedValue. Use the Get method on the Future to retrieve the result of the Side Effect.
MutableSideEffect reduces event history markers
Mutable Side Effects execute the provided function once and look up the History value with the given Workflow ID. They only record a new Marker Event on the Event History if the value for the Side Effect ID changes or is set the first time, whereas every new regular Side Effect call results in a new Marker being recorded.
Workflow timeout and retry policy example in Go
Example showing how to set Workflow timeouts and retry policy:
```go
retrypolicy := &temporal.RetryPolicy{
InitialInterval: time.Second,
BackoffCoefficient: 2.0,
MaximumInterval: time.Second * 100,
}
workflowOptions := client.StartWorkflowOptions{
WorkflowExecutionTimeout: 24 * 365 * 10 * time.Hour,
// WorkflowRunTimeout: 24 * 365 * 10 * time.Hour,
// WorkflowTaskTimeout: 10 * time.Second,
RetryPolicy: retrypolicy,
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
// ...
}
```
RetryPolicy fields for Workflow
RetryPolicy has the following fields: InitialInterval (initial retry interval), BackoffCoefficient (multiplier for exponential backoff), and MaximumInterval (maximum retry interval). These are used to control retry behavior when configured on StartWorkflowOptions.
Workflow Task Timeout in Go
Workflow Task Timeout restricts the maximum amount of time that a Worker can execute a Workflow Task. Set this using the WorkflowTaskTimeout field in StartWorkflowOptions when calling ExecuteWorkflow.
Setting Workflow Timeouts in Go
Create an instance of StartWorkflowOptions from the go.temporal.io/sdk/client package, set the timeout fields (WorkflowExecutionTimeout, WorkflowRunTimeout, or WorkflowTaskTimeout), and pass the instance to the ExecuteWorkflow call.
Workflow Retry Policy in Go
A Retry Policy can work in cooperation with timeouts to provide fine controls to optimize execution experience. Create an instance of RetryPolicy from the go.temporal.io/sdk/temporal package and provide it as the RetryPolicy field of StartWorkflowOptions.
Go NewTimer() function syntax
To set a Timer in Go, use the NewTimer() function and pass the duration you want to wait before continuing. The syntax is: timer := workflow.NewTimer(timerCtx, duration)
Go Sleep() function syntax
To set a sleep duration in Go, use the Sleep() function and pass the duration you want to wait before continuing. The syntax is: sleep = workflow.Sleep(ctx, 10*time.Second). A zero or negative sleep duration causes the function to return immediately.
Example: Getting and setting current workflow details
String currentDetails = Workflow.getCurrentDetails();
Workflow.getLogger(YourWorkflowImpl.class).info("Current details: " + currentDetails);
Workflow.setCurrentDetails("Updated workflow details with new status");
Example: Timer with summary
Workflow.newTimer(Duration.ofMinutes(5),
TimerOptions.newBuilder()
.setSummary("Waiting for payment confirmation")
.build())
.get();
Timer setSummary() in workflow
When creating a TimerOptions within a Workflow using Workflow.newTimer(), use setSummary() to attach a summary to the timer. The input format for setSummary() is a string, limited to 200 bytes. The summary text is shown in the Timeline tab on the Workflow details page.
Example: Workflow startup with static summary and details
WorkflowOptions options = WorkflowOptions.newBuilder()
.setWorkflowId("your-workflow-id")
.setTaskQueue("your-task-queue")
.setStaticSummary("Order processing for customer #12345")
.setStaticDetails("Processing premium order with expedited shipping")
.build();
YourWorkflow workflow = workflowClient.newWorkflowStub(YourWorkflow.class, options);
String result = workflow.yourWorkflowMethod("workflow input");
Workflow interface definition in Java
Define Workflows as an interface annotated with @WorkflowInterface. Use @WorkflowMethod to annotate the workflow method. Example: @WorkflowInterface public interface SayHelloWorkflow { @WorkflowMethod String sayHello(String name); }
Create workflow stub from client
Use client.newWorkflowStub(WorkflowInterface.class, WorkflowOptions) to create a workflow stub. Example: SayHelloWorkflow workflow = client.newWorkflowStub(SayHelloWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue("my-task-queue").setWorkflowId("say-hello-workflow-id").build());
Set workflow ID in workflow options
Specify a unique workflow ID for a workflow execution using WorkflowOptions.newBuilder().setWorkflowId("workflow-id").build().
Workflow code must be deterministic
Workflow code must be deterministic. If you need to call non-deterministic functions such as non-seeded random or UUID.randomUUID() directly from Workflow code, the Temporal SDK provides replay-safe replacements.
Use Activities for non-deterministic operations
For operations like calling external APIs, invoking LLMs, querying databases, or performing I/O, use Activities. Activities run outside Workflow replay and are retried reliably.
Use DynamicWorkflow for default Workflow handling
Use DynamicWorkflow when you need a default Workflow that can handle all Workflow Types that are not registered with a Worker. A single implementation can implement a Workflow Type which by definition is dynamically loaded from some external source. All standard WorkflowOptions and determinism rules apply to Dynamic Workflow implementations.
Workflow logic must not use mutable global variables
Do not use mutable global variables in your Workflow implementations. This ensures that multiple Workflow instances are fully isolated.
Use Workflow.currentTimeMillis() instead of System.currentTimeMillis()
Use Workflow.currentTimeMillis() instead of System.currentTimeMillis() or Instant.now() to get the current time inside a Workflow. It returns the time of the last Workflow Task, which is consistent across replays.
Use Workflow.newRandom() for random numbers
Use Workflow.newRandom() to get a Random instance seeded per Workflow Execution for replay-safe random number generation.
Default Workflow Type naming
The Workflow Type defaults to the short name of the Workflow interface. For example, a Workflow interface named NotifyUserAccounts has a default Workflow Type of NotifyUserAccounts.
Custom Workflow Type with @WorkflowMethod name parameter
To set a custom Workflow Type, use the @WorkflowMethod annotation with the name parameter. Example:
```java
@WorkflowInterface
public interface NotifyUserAccounts {
@WorkflowMethod(name = "your-workflow")
void notify(String[] accountIds);
}
```
When set this way, the name parameter does not have to start with an uppercase letter.
Workflow concurrency features
Only use concurrency features provided by the Workflow class. Multi-threaded code inside a Workflow is executed one thread at a time and under a global lock, so there is no need for explicit synchronization. Call Workflow.sleep instead of Thread.sleep; use Promise and CompletablePromise instead of Future and CompletableFuture; use WorkflowQueue instead of BlockingQueue.
@WorkflowInit constructor example
Example of using @WorkflowInit annotation:
```java
public static class GreetingWorkflowImpl implements GreetingWorkflow {
private final String nameWithTitle;
private boolean titleHasBeenChecked;
@WorkflowInit
public GreetingWorkflowImpl(String input) {
this.nameWithTitle = "Knight " + input;
this.titleHasBeenChecked = false;
}
@Override
public String getGreeting(String input) {
Workflow.await(() -> titleHasBeenChecked);
return "Hello " + nameWithTitle;
}
}
```
Note that the constructor and @WorkflowMethod must have the same parameters.
Workflow.currentTimeMillis() example
Example of getting current time in a Workflow:
```java
long currentTime = Workflow.currentTimeMillis();
```
Use Workflow.randomUUID() for UUIDs
Use Workflow.randomUUID() instead of UUID.randomUUID() to generate replay-safe unique identifiers.
Workflow method parameters recommendation
A method annotated with @WorkflowMethod can have any number of parameters. We recommend passing a single parameter that contains all the input fields to allow for adding fields in a backward-compatible manner.
Custom Workflow parameter example
Example of passing a custom object to a Workflow method:
```java
@WorkflowInterface
public interface YourWorkflow {
@WorkflowMethod
String yourWFMethod(CustomObj customobj);
}
```
Random and UUID example
Example of generating random numbers and UUIDs in a Workflow:
```java
int value = Workflow.newRandom().nextInt(100);
UUID uniqueId = Workflow.randomUUID();
```
Workflow parameters must be serializable
All Workflow Definition parameters must be serializable by the default Jackson JSON Payload Converter. We strongly recommend using objects as parameters so that individual fields may be altered without breaking the Workflow signature.
Workflow interface inheritance example with Signals and Queries
Example of reusable Workflow interface with inheritance:
```java
public interface Retryable {
@SignalMethod
void retryNow();
}
@WorkflowInterface
public interface FileProcessingWorkflow extends Retryable {
@WorkflowMethod
String processFile(Arguments args);
@QueryMethod(name="history")
List<String> getHistory();
@QueryMethod
String getStatus();
@SignalMethod
void abandon();
}
```
WorkflowUnsafe.isReplaying() example
Example of using isReplaying() to emit metrics only on first execution:
```java
import io.temporal.workflow.unsafe.WorkflowUnsafe;
if (!WorkflowUnsafe.isReplaying()) {
emitMetric("workflow_started", 1);
}
```
Workflow return values must be serializable
Workflow return values must also be serializable. Workflow method arguments and return values must be serializable and deserializable using the provided DataConverter.
Dynamic Workflows do not use @WorkflowMethod
When using dynamic Workflows, do not specify a @WorkflowMethod annotation. Instead, implement the DynamicWorkflow interface directly in the Workflow implementation code.
Calling Activities in Workflows
To call Activities in your Workflow, call the Activity implementation. Use ExternalWorkflowStub to start or send Signals from within a Workflow to other running Workflow Executions.
@WorkflowMethod does not apply to inherited interfaces
The interface inheritance approach does not apply to @WorkflowMethod annotations. When using a base interface, it should not include any @WorkflowMethod methods. Attempting to register multiple implementations that both inherit a @WorkflowMethod will fail with IllegalStateException.
Workflow implementation example in Java
Example of a Workflow implementation:
```java
public static class GreetingWorkflowImpl implements GreetingWorkflow {
// implementation code
}
```
DynamicWorkflow execute return type
The execute method for DynamicWorkflow can return type Object. Ensure that your Client can handle an Object type return or is able to convert the Object type response.
Workflow interface inheritance
Workflow interfaces can form inheritance hierarchies to create reusable components across multiple Workflow interfaces. This is useful for scenarios like creating a common Signal that multiple workflows share.
Never branch Workflow logic on replay status
Never use isReplaying() to affect Workflow business logic. Branching on replay status breaks determinism.
Workflow Definition structure in Java
A Workflow Definition in the Java SDK comprises a Workflow interface annotated with @WorkflowInterface and a Workflow implementation that implements the Workflow interface. The Workflow interface must have only one method annotated with @WorkflowMethod.
@WorkflowMethod identifies workflow entry point
The @WorkflowMethod annotation identifies the method that is the starting point of the Workflow Execution. The Workflow Execution completes when this method completes.
Use Workflow.sleep() instead of Thread.sleep()
Use Workflow.sleep() instead of Thread.sleep() for waiting within a Workflow.
Workflow interface example in Java
Example of a Workflow interface definition:
```java
@WorkflowInterface
public interface YourWorkflow {
@WorkflowMethod
String yourWFMethod(Arguments args);
}
```
Use Temporal async functions instead of native Java threads
Use Async.function or Async.procedure provided by the Temporal SDK to execute code asynchronously instead of native Java Thread or other multi-threaded classes like ThreadPoolExecutor.
Terminate a Workflow Execution using WorkflowStub
To terminate a Workflow Execution in Java, use the terminate() function on the WorkflowStub with a reason string. Example: WorkflowStub untyped = WorkflowStub.fromTyped(myWorkflowStub); untyped.terminate("Sample reason");
Cancellation scopes overview
In the Java SDK, Workflows are represented internally by a tree of cancellation scopes, each with cancellation behaviors you can specify. By default, everything runs in the "root" scope. Scopes are created using the Workflow.newCancellationScope constructor. Scopes can be nested, and cancellation propagates from outer scopes to inner ones. A Workflow's method runs in the outermost scope.
Cancel a Workflow Execution using DestroyWorkflowThreadError
When you want to interrupt a Workflow Execution using an error, throw the DestroyWorkflowThreadError. Make sure there isn't any code on that thread to catch this error or it could cause issues with the Temporal service. Workflow code should only ever catch Exception, never Throwable or Error.
CancellationScope API methods
The Java SDK provides the following CancellationScope APIs: CancellationScope.current() gets the current scope. scope.cancel() cancels all operations inside a scope. scope.getCancellationRequest() returns a promise that resolves when a scope cancellation is requested, such as when Workflow code calls cancel() or the entire Workflow is cancelled by an external client.
Handle cancellation with CanceledFailure exception
Cancellations are handled by catching CanceledFailure exceptions thrown by cancelable operations in a Workflow.
Cancel a Workflow Execution using WorkflowStub
To cancel a Workflow Execution in Java, use the cancel() function on the WorkflowStub. Example: WorkflowStub workflowStub = WorkflowStub.fromTyped(workflow); workflowStub.cancel();
Java SDK Workflow documentation sections
The Java SDK documentation covers the following workflow topics: Workflow basics, Child Workflows, Continue-As-New, Message passing, Cancellation, Timeouts, Schedules, Timers, Side effects, Versioning, and Workflow Streams.
Java SDK Workflow.continueAsNew() method
Inside your Workflow, call the Workflow.continueAsNew(ContinueAsNewOptions options, Object... args) function with the same type. This stops the Workflow right away and starts a new one. Example: Workflow.continueAsNew(new ClusterManagerInput(Optional.of(state), input.isTestContinueAsNew()));
Create a Schedule with ScheduleClient
To create a Scheduled Workflow Execution in Java, use the createSchedule() method on the ScheduleClient. When creating the ScheduleClient, you can set a custom Namespace using ScheduleClientOptions. Schedules must be initialized with a Schedule ID. The Schedule is configured using Schedule.newBuilder() with an action (ScheduleActionStartWorkflow) and a spec (ScheduleSpec). Example: ScheduleClient scheduleClient = ScheduleClient.newInstance(service, ScheduleClientOptions.newBuilder().setNamespace("custom_namespace").build()); ScheduleHandle handle = scheduleClient.createSchedule("ScheduleId", schedule, ScheduleOptions.newBuilder().build());
Backfill a Schedule in Java
The backfill action executes Actions ahead of their specified time range, which is useful when you need to execute a missed or delayed Action, or when you want to test the Workflow before its scheduled time. Use the backfill() method on the ScheduleHandle. Example: ScheduleHandle handle = client.getHandle("schedule-id"); Instant now = Instant.now(); handle.backfill(Arrays.asList(new ScheduleBackfill(now.minusMillis(5500), now.minusMillis(2500)), new ScheduleBackfill(now.minusMillis(2500), now)));
Delete a Schedule in Java
To delete a Scheduled Workflow Execution in Java, use the delete() method on the ScheduleHandle. When you delete a Schedule, it does not affect any Workflows that were already started by the Schedule. Example: ScheduleHandle handle = client.getHandle("schedule-id"); handle.delete();