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.