It has been a long time since the latest stable release of EfficientDynamoDb, but I'm glad to announce that v0.9.15 is finally here.
This release brings support for the ReturnValuesOnConditionCheckFailure
parameter in write requests, more predefined region endpoints, improved performance of error parsing, and XML docs for UpdateExpression builder.
Support for ReturnValuesOnConditionCheckFailure
feature
This parameter allows you to receive an item as it existed during the failed write attempt.
It aids in reducing RCU usage and latency for initiating an additional GetItem
request to understand why exactly your condition check failed.
Let's consider the following example. You are developing a warehouse management system or internet store that allows employees to adjust item quantity. A simplified data model for an item might look similar to this:
[DynamoDbTable("items")]
public class Item
{
[DynamoDbProperty("pk", DynamoDbAttributeType.PartitionKey)]
public string WarehouseId { get; set; }
[DynamoDbProperty("sk", DynamoDbAttributeType.SortKey)]
public string ItemId { get; set; }
[DynamoDbProperty("quantity")]
public int Quantity { get; set; }
}
Now, imagine a situation where two employees are trying to sell the same item to customers at the same time. In this case, you need to ensure that there are enough items in the warehouse before you finalize the deal. And if there are not enough items for sale, inform the employee about how many items are currently available.
Before ReturnValuesOnConditionCheckFailure
, the method that performs this function might look similar to this:
public async Task SellItemsAsync(string warehouseId, string itemId, int quantity)
{
try
{
await _context.UpdateItem<Item>()
.WithPrimaryKey(warehouseId, itemId)
.WithCondition(cond => cond.On(x => x.Balance).GreaterThanOrEqualTo(10))
.ExecuteAsync();
}
catch (ConditionalCheckFailedException e)
{
// Not enough items available but no way to tell how many are left.
// So we need to perform an additional GetItem request.
var item = await _context.GetItemAsync<Item>(warehouseId, itemId);
throw new InsufficientInventoryException(item.Balance);
}
}
There are two main issues with this approach:
- Additional RSU is used for the
GetItem
request, which increases your DynamoDB bill. It becomes worse if you consider eventual consistency and opt for strongly consistent reads as they are twice as costly. - Additional latency is added due to a full round trip required for the
GetItem
request.
ReturnValuesOnConditionCheckFailure
addresses both these problems:
public async Task SellItemsAsync(string warehouseId, string itemId, int quantity)
{
try
{
await _context.UpdateItem<Item>()
.WithPrimaryKey(warehouseId, itemId)
.WithCondition(cond => cond.On(x => x.Balance).GreaterThanOrEqualTo(10))
.WithReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.AllOld)
.ExecuteAsync();
}
catch (ConditionalCheckFailedException e)
{
// Now the exception contains `Item` property.
// It will be set only if WithReturnValuesOnConditionCheckFailure is set.
// Note that it's a `Document` type that you can convert to an entity.
var item = _context.ToEntity<Wallet>(e.Item!);
throw new InsufficientInventoryException(item.Balance);
}
}
Using this approach, you receive the balance as it existed at the exact moment of the failed update request, without incurring additional costs or latency in your system.
ReturnValuesOnConditionCheckFailure
is available for all single-item write operations and transactional writes.
More predefined region endpoints
Since the initial release of EfficientDynamoDb, several new AWS regions have been introduced.
While it was always possible to create regions dynamically, all regions supported by DynamoDB are now available as static properties of RegionEndpoint
.
List of new regions added in EfficientDynamoDb 0.9.15:
ap-south-2
- Asia Pacific (Hyderabad)ap-southeast-3
- Asia Pacific (Jakarta)ap-southeast-4
- Asia Pacific (Melbourne)eu-central-2
- Europe (Zurich)eu-south-2
- Europe (Spain)me-central-1
- Middle East (UAE)il-central-1
- Israel (Tel Aviv)
Other improvements
- Error parsing was tuned to handle the most frequent DynamoDB errors more efficiently.
- Added XML docs for UpdateExpression builder to improve developer experience.