-
Notifications
You must be signed in to change notification settings - Fork 412
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
feat(idempotency): support composite primary key in DynamoDBPersistenceLayer #740
Conversation
@@ -20,6 +20,8 @@ def __init__( | |||
self, | |||
table_name: str, | |||
key_attr: str = "id", | |||
key_attr_value: str = "powertools#idempotency", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@heitorlessa, I created this as a Draft PR to get your early feedback on the interface. Once we agree on the ergonomics, I'm happy to update documentation and add examples.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@heitorlessa, I didn't see any feedback so I moved this from Draft to Ready. I would still like to update documentation and examples before merging this PR, and would love some feedback on the API before I take the time to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because DynamoDB IAM resource conditions don't allow you to restrict row level access based on SK, where the function name is known, I'd suggest we change the primary key slightly to: idempotency#function-name
.
If they want, for example, to restrict anyone from ever modifying idempotency tokens for X function that has a prod stage or something more specific to their business in the name they now can.
Here are the scenarios I understood by going through the PR, as C is new - please correct me if I misunderstood them.
Scenarios
A) No hash key set.: Use default hash key and value
from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer
# KEY_ATTR="id"
# KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(table_name="IdempotencyTable")
B) Hash key set.: Use new hash key and default value
# KEY_ATTR="idempotency_key"
# KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(table_name="IdempotencyTable", key_attr="idempotency_key")
C) Hash and Sort key set.: Use new hash and sort key, and default value as sort key
# KEY_ATTR="pk"
# SORT_KEY_ATTR="sk"
# KEY_ATTR_VALUE="idempotency#test-func"
# SORT_KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(
table_name="IdempotencyTable",
key_attr="idempotency_key",
sort_key_attr="idempotency_key")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@heitorlessa, re the scenarios: yes, C is new. I think there is some copy/pasta in the code, the key_attr
and sort_key_attr
should match the comments, as in:
# KEY_ATTR="pk"
# SORT_KEY_ATTR="sk"
# KEY_ATTR_VALUE="idempotency#test-func"
# SORT_KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(
table_name="IdempotencyTable",
key_attr="pk", # <- changed to match comment
sort_key_attr="sk") # <- changed to match comment
There is also a related scenario in which the DynamoDBPersistenceLayer
passes the desired value for key_attr_value
, e.g.:
# KEY_ATTR="pk"
# SORT_KEY_ATTR="sk"
# KEY_ATTR_VALUE="known-static-partition-key-value"
# SORT_KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(
table_name="IdempotencyTable",
key_attr="pk",
key_attr_value="known-static-partition-key-value",
sort_key_attr="sk")
I’m looking at this today, just had an unexpected response from the launch
of public Lambda Layers for this project yesterday ;-)
…On Fri, 8 Oct 2021 at 14:20, Adam Tankanow ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py
<#740 (comment)>
:
> @@ -20,6 +20,8 @@ def __init__(
self,
table_name: str,
key_attr: str = "id",
+ key_attr_value: str = "powertools#idempotency",
@heitorlessa <https://github.com/heitorlessa>, I didn't see any feedback
so I moved this from Draft to Ready. I would still like to update
documentation and examples before merging this PR, and would love some
feedback on the API before I take the time to do that.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#740 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAZPQBDLAITZF4XWVZEJIX3UF3OYDANCNFSM5FOSCTSQ>
.
|
Sorry for poking Heitor. I wasn't sure if the Draft status of the PR kept
it from your busy queue.
On Fri, Oct 8, 2021 at 8:29 AM Heitor Lessa ***@***.***>
wrote:
… I’m looking at this today, just had an unexpected response from the launch
of public Lambda Layers for this project yesterday ;-)
On Fri, 8 Oct 2021 at 14:20, Adam Tankanow ***@***.***> wrote:
> ***@***.**** commented on this pull request.
> ------------------------------
>
> In aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py
> <
#740 (comment)
>
> :
>
> > @@ -20,6 +20,8 @@ def __init__(
> self,
> table_name: str,
> key_attr: str = "id",
> + key_attr_value: str = "powertools#idempotency",
>
> @heitorlessa <https://github.com/heitorlessa>, I didn't see any feedback
> so I moved this from Draft to Ready. I would still like to update
> documentation and examples before merging this PR, and would love some
> feedback on the API before I take the time to do that.
>
> —
> You are receiving this because you were mentioned.
>
>
> Reply to this email directly, view it on GitHub
> <
#740 (comment)
>,
> or unsubscribe
> <
https://github.com/notifications/unsubscribe-auth/AAZPQBDLAITZF4XWVZEJIX3UF3OYDANCNFSM5FOSCTSQ
>
> .
>
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#740 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAQAXC4HQYXOPQXLE66HB6DUF3P2ZANCNFSM5FOSCTSQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
Not at all ;) I was thinking about the cost implications of having a single table for Idempotency -- as in, how would you know whether Idempotency is increasing the overall bill? E.g. if you're Idempotency table is seeing a lot of activities, this is a good chance to verify whether you have a good strategy for tokens. With a single table it's difficult to have this visibility due to other data entities being there. That said, we still should support customers table that use a composite key -- I've got some unexpected meetings but haven't forgot about this yet, and it'll be part of the next release Thank you for the patience @Tankanow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two small changes: 1/ Change PK to something IAM can restrict later, 2/ rollback test fixtures changes so we can do in a separate PR.
@@ -20,6 +20,8 @@ def __init__( | |||
self, | |||
table_name: str, | |||
key_attr: str = "id", | |||
key_attr_value: str = "powertools#idempotency", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because DynamoDB IAM resource conditions don't allow you to restrict row level access based on SK, where the function name is known, I'd suggest we change the primary key slightly to: idempotency#function-name
.
If they want, for example, to restrict anyone from ever modifying idempotency tokens for X function that has a prod stage or something more specific to their business in the name they now can.
Here are the scenarios I understood by going through the PR, as C is new - please correct me if I misunderstood them.
Scenarios
A) No hash key set.: Use default hash key and value
from aws_lambda_powertools.utilities.idempotency import DynamoDBPersistenceLayer
# KEY_ATTR="id"
# KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(table_name="IdempotencyTable")
B) Hash key set.: Use new hash key and default value
# KEY_ATTR="idempotency_key"
# KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(table_name="IdempotencyTable", key_attr="idempotency_key")
C) Hash and Sort key set.: Use new hash and sort key, and default value as sort key
# KEY_ATTR="pk"
# SORT_KEY_ATTR="sk"
# KEY_ATTR_VALUE="idempotency#test-func"
# SORT_KEY_ATTR_VALUE="test-func#ec534ff6b4746107270b412333b59f52"
persistence_layer = DynamoDBPersistenceLayer(
table_name="IdempotencyTable",
key_attr="idempotency_key",
sort_key_attr="idempotency_key")
This is such a good question; I'm delighted to discuss the cost implications! (Actually, my day job is to build an AWS cost intelligence tool on top of serverless tech). There are of many technical solutions here, though I think the key is to think in higher order KPIs. Some questions to ask are "What User Interactions relate to my idempotent queries/updates?" and "What Features, Customers, etc. do those User Interactions roll up to?" That way companies can tie the cost back to user value! The key for this library would be to ensure that clients can set the DynamoDB keys in such a way that they can easily do this analysis without full table scans. |
@@ -64,10 +73,14 @@ def __init__( | |||
|
|||
self._boto_config = boto_config or Config() | |||
self._boto3_session = boto3_session or boto3.session.Session() | |||
if sort_key_attr == key_attr: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NOTE: I snuck in this extra check =).
I'll look into this right after merging the new Event Handle Router, so we can merge this later ;) |
This looks good to me - small nitpicks only! Could we possibly change the name of Also, can we change the variable default to remove the "test-func" part. I understand that code is probably only exercised when testing (outside of a Lambda environment), but it feels wrong to have that in the "real" class. How about letting it be an empty string:
|
Thanks for you patience @heitorlessa and @cakepietoast. I made the Re |
Apologies for the late response on this one, I missed your reply. I understand your point that "Key attribute value" sounds like we're setting the value of the "key attribute", which to my mind is saying the same thing as setting the "key attribute". What we're actually doing is setting a static value to use for the partition key, which is where my suggestion came from. Do you feel any better about |
I like |
Much appreciated! |
Done. Ready for re-review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Issue #694
Description of changes:
Add new optional parameters,
key_attr_value
andsort_key_attr
, to DynamoDBPersistenceLayer. Ifsort_key_attr
is set, then DynamoDBPersistenceLayer will use a composite primary key with the partition key set to a static value, defaults topowertools#idempotency
, and the sort key set to the hashed idempotency key.Checklist
Breaking change checklist
RFC issue #:
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.