Heres the System I'm trying to create in DynamoDB:
We have a set of Users, each of which has an inventory. This inventory is filled with different types of items. Users can transfer items from one Inventory to another through trades. Some items are also perishable after a certain number of hours, like contracts or food). On of the big problems is, that the perishability of items means I probably need a new table for the items instead of just having them all sit in the same row as the user. Theres also a 400KB limit per row in dynamoDB, which may be exceeded by large inventories. The whole thing should be a rest interface.
I had a sort of basic way of solving it, although I don't think its very practical:
a trade looks like this:
{
user1:{user-name},
user2:{user-name}, < partition key
from_user1_to_user2:
{
{item_id1},
{item_id2},
{item_id3},
...
{item_idn},
}
from_user2_to_user1:
{
{item_id1},
{item_id2},
{item_id3},
...
{item_idn},
}
state:"open"/"accepted"/"rejected"#{guid} < composite sort key
}
Items look like this:
{
id: {user_name} < regular partion key
sort: {type}#{guid} < regular sort key
id_gsi:{perish_hour} < gsi parition key conisting of perish time as unix timestamp mod 3600
sort_gsi:{guid}
type:{type}
other_attributes: ...
}
And a user looks like this:
{
username:{name} < partition key
inventory_locked:true/false < if true, adding new items to the inventory or trades are temporarily locked, which is done through dynamodb transactions
}
Items a bit complicated. They can either be queried by the user they belong to or by the hour in which they perish.
Now since the perishment of items doesn't really have to be precise (although it would perhaps be good if it was), its not too hard to implement. Create a cronjob lambda that runs every hour that keeps deleting items that are scheduled to perish until there are none left, using the GSI time partition key.
The trades however have to be guaranteed to be atomic. But a user should be able to trade at least 40 items simultaneously, which is made impossible by DynamoDBs 25 item atomic transaction limit.
In order to offer a trade, a User (user1) sends a POST request containing a JSON object like the one above, just without the state parameter, which lambda sets to open automatically. The recipient (users2) will query for open trade requests. He sends a PATCH request changing only the state to either accepted or rejected.
now a lambda function for the patch request is started:
- User 2 accepts a trade through a Patch request
- both user1 and user2 get their inventories locked
- now the lambda function transfers the items batch by batch (because of lambdas batch limit), until are items are transferred (this would require multiple roundtrips though, which hinders performance)
- both user1 and user2 get their inventories unlocked and can trade again
- if everything went well, a status code of 200 is sent to user2
now this solution has multiple issues. If theres a problem with the transferal of items, both users inventories remain locked for ever. There could also be problems with item duplication. This could happen for example if a perishable item is deleted before the transaction is finished.
Is there a better solution to this or a way to improve my solution?