See: Description
Interface | Description |
---|---|
ActivityStub |
ActivityStub is used to call an activity without referencing an interface it implements.
|
CancellationScope |
Handle to a cancellation scope created through
Workflow.newCancellationScope(Runnable) or
Workflow.newDetachedCancellationScope(Runnable) . |
ChildWorkflowStub |
Supports starting and signalling child workflows by the name and list of arguments.
|
CompletablePromise<V> |
Promise that exposes completion methods. |
DynamicQueryHandler |
Use DynamicQueryHandler to process any query dynamically.
|
DynamicSignalHandler |
Use DynamicSignalHandler to process any signal dynamically.
|
DynamicWorkflow |
Use DynamicWorkflow to implement any number of workflow types dynamically.
|
ExternalWorkflowStub |
Supports signalling and cancelling any workflows by the workflow type and their id.
|
Functions.Func<R> | |
Functions.Func1<T1,R> | |
Functions.Func2<T1,T2,R> | |
Functions.Func3<T1,T2,T3,R> | |
Functions.Func4<T1,T2,T3,T4,R> | |
Functions.Func5<T1,T2,T3,T4,T5,R> | |
Functions.Func6<T1,T2,T3,T4,T5,T6,R> | |
Functions.Proc | |
Functions.Proc1<T1> | |
Functions.Proc2<T1,T2> | |
Functions.Proc3<T1,T2,T3> | |
Functions.Proc4<T1,T2,T3,T4> | |
Functions.Proc5<T1,T2,T3,T4,T5> | |
Functions.Proc6<T1,T2,T3,T4,T5,T6> | |
Functions.TemporalFunctionalInterfaceMarker | |
Promise<V> |
Contains result of an asynchronous computation.
|
QueueConsumer<E> | |
QueueProducer<E> | |
WorkflowInfo | |
WorkflowQueue<E> |
Class | Description |
---|---|
Async |
Supports invoking lambdas and activity and child workflow references asynchronously.
|
ChildWorkflowOptions | |
ChildWorkflowOptions.Builder | |
ContinueAsNewOptions |
This class contain overrides for continueAsNew call.
|
ContinueAsNewOptions.Builder | |
Functions | |
Saga |
This class implements the logic to execute compensation operations that is
often required in Saga applications.
|
Saga.Options | |
Saga.Options.Builder | |
Workflow |
This class contains methods exposing Temporal API for Workflows, like
Creation and scheduling of activities, child workflows, external workflows, continue-as-new
runs
Operations over workflow elements, like Side Effects, Timers, Versions,
CancellationScope
Accessing and updating of the workflow data, like WorkflowInfo , Memos and Search
Attributes
Deterministic implementation of popular non-deterministic API working with time, logging
and generation of random values
Methods of this class are intended to be called from a workflow method only until explicitly
stated otherwise on the specific method's javadoc. |
WorkflowLocal<T> |
A value that is local to a single workflow execution.
|
WorkflowThreadLocal<T> |
ThreadLocal analog for workflow code. |
Enum | Description |
---|---|
ChildWorkflowCancellationType |
Defines behaviour of the parent workflow when
CancellationScope that wraps child workflow
execution request is canceled. |
Exception | Description |
---|---|
CancelExternalWorkflowException |
Exception used to communicate failure of a request to cancel an external workflow.
|
Saga.CompensationException | |
SignalExternalWorkflowException |
Exception used to communicate failure of a request to signal an external workflow.
|
Annotation Type | Description |
---|---|
QueryMethod |
Indicates that the method is a query method.
|
SignalMethod |
Indicates that the method is a signal handler method.
|
WorkflowInterface |
WorkflowInterface annotation indicates that an interface is a Workflow interface.
|
WorkflowMethod |
Indicates that the method is a workflow method.
|
WorkflowMethod
indicates an entry point to a
workflow. It contains parameters such as timeouts and a task queue. Required parameters
(like workflowRunTimeoutSeconds
) that are not specified through the annotation must
be provided at runtime.
SignalMethod
indicates a method that reacts to
external signals. It must have a void
return type.
QueryMethod
indicates a method that reacts to
synchronous query requests. You can have more than one method with the same annotation.
public interface FileProcessingWorkflow {
@WorkflowMethod(workflowRunTimeoutSeconds = 10, taskQueue = "file-processing")
String processFile(Arguments args);
@QueryMethod(name="history")
List getHistory();
@QueryMethod(name="status")
String getStatus();
@SignalMethod
void retryNow();
}
WorkflowClient
WorkflowMethod
is invoked. As soon as this method returns the workflow,
execution is closed. While workflow execution is open, it can receive calls to signal and query
methods. No additional calls to workflow methods are allowed. The workflow object is stateful, so
query and signal methods can communicate with the other parts of the workflow through workflow
object fields.
Workflow.newActivityStub(Class)
returns a client-side stub that
implements an activity interface. It takes activity type and activity options as arguments.
Activity options are needed only if some of the required timeouts are not specified through the
@ActivityMethod
annotation.
Calling a method on this interface invokes an activity that implements this method. An activity invocation synchronously blocks until the activity completes, fails, or times out. Even if activity execution takes a few months, the workflow code still sees it as a single synchronous invocation. Isn't it great? It doesn't matter what happens to the processes that host the workflow. The business logic code just sees a single method call.
public class FileProcessingWorkflowImpl implements FileProcessingWorkflow {
private final FileProcessingActivities activities;
public FileProcessingWorkflowImpl() {
this.store = Workflow.newActivityStub(FileProcessingActivities.class);
}
@Override
public void processFile(Arguments args) {
String localName = null;
String processedName = null;
try {
localName = activities.download(args.getSourceBucketName(), args.getSourceFilename());
processedName = activities.processFile(localName);
activities.upload(args.getTargetBucketName(), args.getTargetFilename(), processedName);
} finally {
if (localName != null) { // File was downloaded.
activities.deleteLocalFile(localName);
}
if (processedName != null) { // File was processed.
activities.deleteLocalFile(processedName);
}
}
}
...
}
If different activities need different options, like timeouts or a task queue, multiple
client-side stubs can be created with different options.
public FileProcessingWorkflowImpl() {
ActivityOptions options1 = ActivityOptions.newBuilder()
.setTaskQueue("taskQueue1")
.build();
this.store1 = Workflow.newActivityStub(FileProcessingActivities.class, options1);
ActivityOptions options2 = ActivityOptions.newBuilder()
.setTaskQueue("taskQueue2")
.build();
this.store2 = Workflow.newActivityStub(FileProcessingActivities.class, options2);
}
Async
static methods allow you to invoke any activity asynchronously. The
call returns a Promise
result immediately. Promise
is similar to both Future
and CompletionStage
. The Promise.get()
blocks
until a result is available. It also exposes the Promise.thenApply(Functions.Func1)
and Promise.handle(Functions.Func2)
methods. See the Promise
documentation for technical details about differences with Future
.
To convert a synchronous call
String localName = activities.download(sourceBucket, sourceFile);
to asynchronous style, the method reference is passed to Async.function(Functions.Func)
or Async.procedure(Functions.Proc)
followed by activity arguments:
Promise localNamePromise = Async.function(activities::download, sourceBucket, sourceFile);
Then to wait synchronously for the result:
String localName = localNamePromise.get();
Here is the above example rewritten to call download and upload in parallel on multiple files:
public void processFile(Arguments args) {
List<Promise<String>> localNamePromises = new ArrayList<>();
List<String> processedNames = null;
try {
// Download all files in parallel.
for (String sourceFilename : args.getSourceFilenames()) {
Promise<String> localName = Async.function(activities::download, args.getSourceBucketName(), sourceFilename);
localNamePromises.add(localName);
}
// allOf converts a list of promises to a single promise that contains a list of each promise value.
Promise<List<String>> localNamesPromise = Promise.allOf(localNamePromises);
// All code until the next line wasn't blocking.
// The promise get is a blocking call.
List<String> localNames = localNamesPromise.get();
processedNames = activities.processFiles(localNames);
// Upload all results in parallel.
List<Promise<Void>> uploadedList = new ArrayList<>();
for (String processedName : processedNames) {
Promise<Void> uploaded = Async.procedure(activities::upload,
args.getTargetBucketName(),
args.getTargetFilename(),
processedName);
uploadedList.add(uploaded);
}
// Wait for all uploads to complete.
Promise<?> allUploaded = Promise.allOf(uploadedList);
allUploaded.get(); // blocks until all promises are ready.
} finally {
// Execute deletes even if workflow is canceled.
Workflow.newDetachedCancellationScope(
() -> {
for (Promise<Sting> localNamePromise : localNamePromises) {
// Skip files that haven't completed downloading.
if (localNamePromise.isCompleted()) {
activities.deleteLocalFile(localNamePromise.get());
}
}
if (processedNames != null) {
for (String processedName : processedNames) {
activities.deleteLocalFile(processedName);
}
}
}
).run();
}
}
Workflow.newChildWorkflowStub(Class)
returns a client-side stub
that implements a child workflow interface. It takes a child workflow type and optional child
workflow options as arguments. Workflow options may be needed to override the timeouts and task
queue if they differ from the ones defined in the @WorkflowMethod
annotation or parent workflow.
The first call to the child workflow stub must always be to a method annotated with
@WorkflowMethod
. Similarly to activities, a call can be
synchronous or asynchronous using Async.function(Functions.Func)
or
Async.procedure(Functions.Proc)
. The synchronous call blocks until a
child workflow completes. The asynchronous call returns a Promise
that can be used to wait for the completion. After an async call returns the stub, it can be used
to send signals to the child by calling methods annotated with @SignalMethod
. Querying a child workflow by calling methods annotated with
@QueryMethod
from within workflow code is not supported.
However, queries can be done from activities using the WorkflowClient
provided stub.
public interface GreetingChild {
@WorkflowMethod
String composeGreeting(String greeting, String name);
}
public static class GreetingWorkflowImpl implements GreetingWorkflow {
@Override
public String getGreeting(String name) {
GreetingChild child = Workflow.newChildWorkflowStub(GreetingChild.class);
// This is a blocking call that returns only after child has completed.
return child.composeGreeting("Hello", name );
}
}
Running two children in parallel:
public static class GreetingWorkflowImpl implements GreetingWorkflow {
@Override
public String getGreeting(String name) {
// Workflows are stateful, so a new stub must be created for each new child.
GreetingChild child1 = Workflow.newChildWorkflowStub(GreetingChild.class);
Promise greeting1 = Async.function(child1::composeGreeting, "Hello", name);
// Both children will run concurrently.
GreetingChild child2 = Workflow.newChildWorkflowStub(GreetingChild.class);
Promise greeting2 = Async.function(child2::composeGreeting, "Bye", name);
// Do something else here.
...
return "First: " + greeting1.get() + ", second=" + greeting2.get();
}
}
To send signal to a child, call a method annotated with @SignalMethod
:
public interface GreetingChild {
@WorkflowMethod
String composeGreeting(String greeting, String name);
@SignalMethod
void updateName(String name);
}
public static class GreetingWorkflowImpl implements GreetingWorkflow {
@Override
public String getGreeting(String name) {
GreetingChild child = Workflow.newChildWorkflowStub(GreetingChild.class);
Promise greeting = Async.function(child::composeGreeting, "Hello", name);
child.updateName("Temporal");
return greeting.get();
}
}
Calling methods annotated with @QueryMethod
is not
allowed from within a workflow code.
.currentTimeMillis()
or UUID.randomUUID()
directly form the workflow
code. Always do this in activities.
Workflow
as safe deterministic alternatives to
non-deterministic methods. For example, only use Workflow.currentTimeMillis()
to get the current time inside a
workflow.
Thread
or any other multi-threaded classes like
ThreadPoolExecutor
. Use Async.function(Functions.Func)
or Async.procedure(Functions.Proc)
to execute code asynchronously.
Workflow.sleep(Duration)
instead of Thread.sleep(long)
.
Promise
and CompletablePromise
instead of Future
and
CompletableFuture
.
WorkflowQueue
instead of BlockingQueue
.
DataConverter
. The default implementation uses the JSON
serializer, but any alternative serialization mechanism is pluggable.
The values passed to workflows through invocation parameters or returned through a result value are recorded in the execution history. The entire execution history is transferred from the Temporal service to workflow workers with every event that the workflow logic needs to process. A large execution history can thus adversely impact the performance of your workflow. Therefore, be mindful of the amount of data that you transfer via activity invocation parameters or return values. Other than that, no additional limitations exist on activity implementations.