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.