Feature request: Create a dedicated Cache utility in Powertools (based on current idempotency layer)
Opened this issue · 4 comments
Use case
Customers are using the Powertools Idempotency utility for caching purposes. Idempotency is a specific implementation that includes a "caching" mechanism via the storage provider classes. Idempotency is a particular use case, and there is inbuilt functionality for dealing with the records in a specific way which I feel is dangerous for caching use cases.
Solution/User Experience
from aws_lambda_powertools.utilities.caching import (
DynamoDBPersistenceLayer,
Cache,
)
table = os.getenv("CACHE_TABLE", "")
persistence_layer = DynamoDBPersistenceLayer(table_name=table)
cache = Cache(persistence_store=peristsance_layer)
my_ttl = 300
def lambda_handler(event: dict, context: LambdaContext):
try:
previous_value = cache.get(event.order_id, "default_value")
payment: Payment = create_subscription_payment(event, previous_value)
cache.set(order_id, payment.detail, my_ttl)
return {
"payment_id": payment.payment_id,
"message": "success",
"statusCode": 200,
}
except Exception as exc:
raise PaymentError(f"Error creating payment {str(exc)}")
def create_subscription_payment(event: dict) -> Payment:
return Payment(**event)
Alternative solutions
Acknowledgment
- This feature request meets Powertools for AWS Lambda (Python) Tenets
- Should this be considered in other Powertools for AWS Lambda languages? i.e. Java, TypeScript, and .NET
The idea of this feature request is to look at creating a new Caching feature for Powertools, separate from the Idempotency utility, which is not built for caching (not exactly).
Another addition for caching would be to add a decorator to enable cached data to be injected into a handler, similar to the following. the decorator would fetch from cache the value based on the jmespath event key and could also incorportae a custom internal LRU memory cache so we only go to the database when we have to (in case of multiple cahce lookups for same key across several transactiosn):
from aws_lambda_powertools.utilities.caching import (
DynamoDBPersistenceLayer,
lru_cache,
)
table = os.getenv("CACHE_TABLE", "")
persistence_layer = DynamoDBPersistenceLayer(table_name=table)
@lru_cache(persistance_store=persistance_layer, ttl=300, event_key_jmespath="order_id")
def lambda_handler(event: dict, context: LambdaContext):
try:
previous_value = app.cache.get(order_id)
payment: Payment = create_subscription_payment(event, previous_value)
cache.set(order_id, payment.detail, my_ttl)
return {
"payment_id": payment.payment_id,
"message": "success",
"statusCode": 200,
}
except Exception as exc:
raise PaymentError(f"Error creating payment {str(exc)}")
def create_subscription_payment(event: dict) -> Payment:
return Payment(**event)@walmsles - Really love the idea of this! A really nice addition to powertools! The lru_cache would be such a nice utility to have in lambda.
I am curious on how a user can manage the cache externally. In this new potential cache utility would the original key be stored in a manner that it can be managed from a completely different service or lambda function.
For example, in the case of an order stored by order_id, if another lambda function is responsible for canceling the order and we need to delete it from the cache. Is there a way to look up the cache item and delete it manually? Or would that require the second feature #7071 to be completed as well?
I didn't make it clear in first writeup. The cache will use a storage provider class much like Idempotency does. Therefore storage would be used to persist the cached item allowing multiple lambda to access cachn storage and the same key.
I am planning to do more research on best DevEx. The lru-cache idea would combine an internal short term memory cache allowing multiple accesses (across distinct invocations) without needing to go back to storage.
I like being able to inject cached items through a decorator which fits a lot of the utility use cases today and using jmespath works nice for most use cases.
#7071 is a seperate feature I feel is useful to improve function hooks and is unrelated given this cache utility will work for your use case better.
I think we're still looking into this, I'll bring this issue up in the next planning meeting.