AWS Developer Tools Blog
Waiters in the AWS SDK for Java
We’re pleased to announce the addition of the waiters feature in the AWS SDK for Java (take a look at the release notes). Waiters make it easier to wait for a resource to transition into a desired state, which is a very common task when you’re working with services that are eventually consistent (such as Amazon DynamoDB) or have a lead time for creating resources (such as Amazon EC2). Before waiters, it was difficult to come up with the polling logic to determine whether a particular resource had transitioned into a desired state. Now with waiters, you can more simply and easily abstract out the polling logic into a simple API call.
Polling without Waiters
For example, let’s say you wanted to create a DynamoDB table and access it soon after it’s created to add an item into it. There’s a chance that if the table isn’t created already, a ResourceNotFoundException error will be thrown. In this scenario, you have to poll until the table becomes active and ready for use.
//Create an AmazonDynamoDb client
AmazonDynamoDB client = AmazonDynamoDBClientBuilder
.standard()
.withRegion(Regions.US_WEST_2)
.build();
//Create a table
client.createTable(new CreateTableRequest().withTableName(tableName)
.withKeySchema(new KeySchemaElement().withKeyType(KeyType.HASH)
.withAttributeName("hashKey"))
.withAttributeDefinitions(new AttributeDefinition()
.withAttributeType(ScalarAttributeType.S)
.withAttributeName("hashKey"))
.withProvisionedThroughput(new ProvisionedThroughput(5L, 5L)));
Without waiters, polling would look like this.
//Polling 5 times for table to become active
int attempts = 0;
while(attempts < 5){
try{
DescribeTableRequest request = new DescribeTableRequest(tableName);
DescribeTableResult result = client.describeTable(request);
String status = res.getTable().getTableStatus();
if(status.equals(“ACTIVE”)){
break;
}
Thread.sleep(5000);
attempts++;
}
catch(ResourceNotFoundException e){
}
}
Polling with Waiters
Waiters make it easier to abstract out the polling logic into a simple API call. Let’s take a look at how you can create and use waiters to more easily determine whether a DynamoDB table is successfully created and ready to use for further transactions.
//Create waiter to wait on successful creation of table.
Waiter waiter = client.waiters().tableExists();
try{
waiter.run(new WaiterParameters<>(new DescribeTableRequest(tableName));
}
catch(WaiterUnrecoverableException e){
//Explicit short circuit when the resource transitions into
//an undesired state.
}
catch(WaiterTimedOutException e){
//Failed to transition into desired state even after polling
}
catch(DynamoDBException e){
//Unexpected service exception
}
For more details, see AmazonDynamoDBWaiters.
Async Waiters
We also offer an async variant of waiters that returns a Future object that promises to hold the result of the computation after it’s done. An async waiter requires a callback interface that is invoked after the Future object is fulfilled. Callback provides an interface to carry out other tasks, depending on whether the resource entered a desired state (onWaitSuccess) or not (onWaitFailure).
To use an async waiter, you must call an async variant of run.
Future future = client.waiters()
.tableExists()
.runAsync(new WaiterParameters()
.withRequest(new DescribeTableRequest(tableName)),
new WaiterHandler() {
@Override
public void onWaitSuccess(DescribeTableRequest request) {
System.out.println("Table creation success!!!!!");
}
@Override
public void onWaitFailure(Exception e) {
e.printStackTrace();
}
});
future.get(5, TimeUnit.MINUTES);
To learn more, see Waiters.
We are excited about this new addition to the SDK! Let us know what you think in the comments section below.