HelloWorldWorkflowAsync Application
Sometimes, it's preferable to have a workflow perform certain tasks locally instead of using
an activity. However, workflow tasks often involve processing the values represented by
Promise<T> objects. If you pass a Promise<T> object to a
synchronous workflow method, the method executes immediately but it can't access the
Promise<T> object's value until the object is ready. You could poll
Promise<T>.isReady until it returns true, but that's
inefficient and the method might block for a long time. A better approach is to use an
asynchronous method.
An asynchronous method is implemented much like a standard method—often as a member
of the workflow implementation class—and runs in the workflow implementation's context.
You designate it as an asynchronous method by applying an @Asynchronous annotation,
which directs the framework to treat it much like an activity.
-
When a workflow implementation calls an asynchronous method, it returns immediately. Asynchronous methods typically return a
Promise<T>object, which becomes ready when the method completes. -
If you pass an asynchronous method one or more
Promise<T>objects, it defers execution until all the input objects are ready. An asynchronous method can therefore access its inputPromise<T>values without risking an exception.
Note
Because of the way that the AWS Flow Framework for Java executes the workflow, asynchronous methods typically execute multiple times, so you should use them only for quick low-overhead tasks. You should use activities to perform lengthy tasks such as large computations. For details, see AWS Flow Framework Basic Concepts: Distributed Execution.
This topic is a walkthrough of HelloWorldWorkflowAsync, a modified version of HelloWorldWorkflow that replaces one of the activities with an asynchronous method. To implement the application, create a copy of the helloWorld.HelloWorldWorkflow package in your project directory and name it helloWorld.HelloWorldWorkflowAsync.
Note
This topic builds on the concepts and files presented in the HelloWorld Application and HelloWorldWorkflow Application topics. Familiarize yourself with the files and concepts presented in those topics before proceeding.
The following sections describe how to modify the original HelloWorldWorkflow code to use an asynchronous method.
HelloWorldWorkflowAsync Activities Implementation
HelloWorldWorkflowAsync implements its activities worker interface in
GreeterActivities, as follows:
import com.amazonaws.services.simpleworkflow.flow.annotations.Activities; import com.amazonaws.services.simpleworkflow.flow.annotations.ActivityRegistrationOptions; @Activities(version="2.0") @ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300, defaultTaskStartToCloseTimeoutSeconds = 10) public interface GreeterActivities { public String getName(); public void say(String what); }
This interface is similar to the one used by HelloWorldWorkflow, with the following exceptions:
-
It omits the
getGreetingactivity; that task is now handled by an asynchronous method. -
The version number is set to 2.0. After you have registered an activities interface with Amazon SWF, you can't modify it unless you change the version number.
The remaining activity method implementations are identical to HelloWorldWorkflow. Just
delete getGreeting from GreeterActivitiesImpl.
HelloWorldWorkflowAsync Workflow Implementation
HelloWorldWorkflowAsync defines the workflow interface as follows:
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute; import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow; import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions; @Workflow @WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 3600) public interface GreeterWorkflow { @Execute(version = "2.0") public void greet(); }
The interface is identical to HelloWorldWorkflow apart from a new version number. As with activities, if you want to change a registered workflow, you must change its version.
HelloWorldWorkflowAsync implements the workflow as follows:
import com.amazonaws.services.simpleworkflow.flow.annotations.Asynchronous; import com.amazonaws.services.simpleworkflow.flow.core.Promise; public class GreeterWorkflowImpl implements GreeterWorkflow { private GreeterActivitiesClient operations = new GreeterActivitiesClientImpl(); @Override public void greet() { Promise<String> name = operations.getName(); Promise<String> greeting = getGreeting(name); operations.say(greeting); } @Asynchronous private Promise<String> getGreeting(Promise<String> name) { String returnString = "Hello " + name.get() + "!"; return Promise.asPromise(returnString); } }
HelloWorldWorkflowAsync replaces the getGreeting activity with a
getGreeting asynchronous method but the greet method works in much
the same way:
-
Execute the
getNameactivity, which immediately returns aPromise<String>object,name, that represents the name. -
Call the
getGreetingasynchronous method and pass it thenameobject.getGreetingimmediately returns aPromise<String>object,greeting, that represents the greeting. -
Execute the
sayactivity and pass it thegreetingobject. -
When
getNamecompletes,namebecomes ready andgetGreetinguses its value to construct the greeting. -
When
getGreetingcompletes,greetingbecomes ready andsayprints the string to the console.
The difference is that, instead of calling the activities client to execute a
getGreeting activity, greet calls the asynchronous getGreeting
method. The net result is the same, but the getGreeting method works somewhat
differently than the getGreeting activity.
-
The workflow worker uses standard function call semantics to execute
getGreeting. However, the asynchronous execution of the activity is mediated by Amazon SWF. -
getGreetingruns in the workflow implementation's process. -
getGreetingreturns aPromise<String>object rather than aStringobject. To get the String value held by thePromise, you call itsget()method. However, because the activity is being run asynchronously, its return value might not be ready immediately;get()will raise an exception until the return value of the asynchronous method is available.For more information about how
Promiseworks, see AWS Flow Framework Basic Concepts: Data Exchange Between Activities and Workflows.
getGreeting creates a return value by passing the greeting string to the
static Promise.asPromise method. This method creates a
Promise<T> object of the appropriate type, sets the value, and puts it in
the ready state.
HelloWorldWorkflowAsync Workflow and Activities Host and Starter
HelloWorldWorkflowAsync implements GreeterWorker as the host class for the
workflow and activity implementations. It is identical to the HelloWorldWorkflow
implementation except for the taskListToPoll name, which is set to
"HelloWorldAsyncList".
import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow; import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient; import com.amazonaws.services.simpleworkflow.flow.ActivityWorker; import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker; public class GreeterWorker { public static void main(String[] args) throws Exception { ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000); String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID"); String swfSecretKey = System.getenv("AWS_SECRET_KEY"); AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey); AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config); service.setEndpoint("https://swf.us-east-1.amazonaws.com"); String domain = "helloWorldWalkthrough"; String taskListToPoll = "HelloWorldAsyncList"; ActivityWorker aw = new ActivityWorker(service, domain, taskListToPoll); aw.addActivitiesImplementation(new GreeterActivitiesImpl()); aw.start(); WorkflowWorker wfw = new WorkflowWorker(service, domain, taskListToPoll); wfw.addWorkflowImplementationType(GreeterWorkflowImpl.class); wfw.start(); } }
HelloWorldWorkflowAsync implements the workflow starter in GreeterMain; it is
identical to the HelloWorldWorkflow implementation.
To execute the workflow, run GreeterWorker and GreeterMain, just
as with HelloWorldWorkflow.