Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use DynamoDB for persistence. #97

Closed
joshprzybyszewski opened this issue Aug 29, 2021 · 5 comments
Closed

Use DynamoDB for persistence. #97

joshprzybyszewski opened this issue Aug 29, 2021 · 5 comments
Assignees

Comments

@joshprzybyszewski
Copy link
Owner

joshprzybyszewski commented Aug 29, 2021

I think this will have 5 main stages:

  1. Get dynamoDB stood up in a local environment (using docker-compose)
  2. decide what the table schema needs to look like (database architecture is probably more important than many architectural decisions you make).
  3. Use the mongodb code as a starting point to get all of the services created for dynamodb
  4. figure out how reading/writing works in the local app against a local dynamoDB
  5. add dynamodb to the aws deployed app using the CDK like everything else.

The goal:
Have an infrastructure that isn't going to be constantly charging me (ahem RDS) when it's deployed; only use for the requests that the app needs. This would unlock serverless deploy of the app as well.

@joshprzybyszewski joshprzybyszewski self-assigned this Aug 29, 2021
@joshprzybyszewski
Copy link
Owner Author

joshprzybyszewski commented Aug 30, 2021

For goal 2, here is my current thought process:

From the best practices:

You should maintain as few tables as possible in a DynamoDB application.

--> So we should shoot to have a single dynamo table for this application.

We don't want to hit collisions on IDs between games and players. We want to be able to have a single game grouped close enough together (so likely put a gameID in a single partition, and then have a sortKey to iterate through time, similar to this example).

💡 how about this for a schema design (rough commit):

PartitionKey: String Identifier (GameID|PlayerID)
SortKey: String "descriptor" (`action$actionNumber`|`interaction`|`person`)

@cszczepaniak
Copy link
Collaborator

cszczepaniak commented Aug 30, 2021

How can we know actionNumber given several users playing the same game simultaneously? Do we have to query dynamo for the latest action number?

Or do we use a timestamp (maybe just Unix() or UnixNano()) to guarantee that it's monotonically increasing and we'd only have collisions if users do actions on the exact same milli/nanosecond?

@joshprzybyszewski
Copy link
Owner Author

joshprzybyszewski commented Aug 30, 2021

Great question! How important is consistency to us? If we want to ensure that two players playing the same game will never "accidentally" stomp on each others' actions, then we must use some strong consistency/transactions to ensure that we are only ever in the process of applying one player's update at a time. Using a timestamp is one way to try and achieve this consistency, but is not infallible (however, it's highly unlikely considering we only ever have at max 4 players per game. In applications with higher scales, this solution would be right out because that likelihood goes up with the number of actors). The best way is to apply a transaction at the GameID level (like the SQL solution has) so that only one action can ever be in-process across all containers at a given time.

Another possible solution is to use the "number of previous actions" as the actionNumber in question. that is, a player doing an action can know what number they are because they've seen all N actions done before them, so they will apply action N+1. This is even more prone to stomping because two users could contribute cards to the crib without "looking up" and seeing that the other player had done the same. In this case of stomping, one player would be confused and would have to re-submit their entry because they'd been stomped on by another player.

So how important is consistency? If most players aren't ever going to stomp on each other, I think it's ok to do this without transactional guarantees (like the SQL solution) because the worst case is that someone has to do something twice (which is a bad user experience, but this is a free-time hobby cribbage project:#). If dynamoDB offers transactions, perhaps that would be worth investigating...

@cszczepaniak
Copy link
Collaborator

cszczepaniak commented Aug 30, 2021

Transactionality would be the sure-fire way to go, but given:

  1. We're a hobby application
  2. The fail case isn't catastrophic
  3. Even with a large number of actors, something like UnixNano() would be highly unlikely to collide

I'm not sure it's a "must have" (as you mentioned)

Of course, the other (completely overkill, probably) option would be to use a FIFO queue 😎

@joshprzybyszewski
Copy link
Owner Author

We have completed the work to add dynamo db as persistence in #101

I have documented transactionality in #106

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants