8
8
from typing import Any , Literal , Protocol
9
9
10
10
import redis
11
- from typing_extensions import deprecated
11
+ from typing_extensions import TypeAlias , deprecated
12
12
13
13
from aws_lambda_powertools .utilities .idempotency import BasePersistenceLayer
14
14
from aws_lambda_powertools .utilities .idempotency .exceptions import (
@@ -88,7 +88,7 @@ def __init__(
88
88
host : str = "" ,
89
89
port : int = 6379 ,
90
90
username : str = "" ,
91
- password : str = "" , # nosec - password for Redis connection
91
+ password : str = "" , # nosec - password for Cache connection
92
92
db_index : int = 0 ,
93
93
mode : Literal ["standalone" , "cluster" ] = "standalone" ,
94
94
ssl : bool = True ,
@@ -131,7 +131,7 @@ def __init__(
131
131
132
132
from aws_lambda_powertools.utilities.typing import LambdaContext
133
133
134
- persistence_layer = RedisCachePersistenceLayer (host="localhost", port=6379)
134
+ persistence_layer = CachePersistenceLayer (host="localhost", port=6379)
135
135
136
136
137
137
@dataclass
@@ -184,15 +184,15 @@ def _init_client(self) -> RedisClientProtocol:
184
184
185
185
try :
186
186
if self .url :
187
- logger .debug (f"Using URL format to connect to Redis : { self .host } " )
187
+ logger .debug (f"Using URL format to connect to Cache : { self .host } " )
188
188
return client .from_url (url = self .url )
189
189
else :
190
- # Redis in cluster mode doesn't support db parameter
190
+ # Cache in cluster mode doesn't support db parameter
191
191
extra_param_connection : dict [str , Any ] = {}
192
192
if self .mode != "cluster" :
193
193
extra_param_connection = {"db" : self .db_index }
194
194
195
- logger .debug (f"Using arguments to connect to Redis : { self .host } " )
195
+ logger .debug (f"Using arguments to connect to Cache : { self .host } " )
196
196
return client (
197
197
host = self .host ,
198
198
port = self .port ,
@@ -203,8 +203,8 @@ def _init_client(self) -> RedisClientProtocol:
203
203
** extra_param_connection ,
204
204
)
205
205
except redis .exceptions .ConnectionError as exc :
206
- logger .debug (f"Cannot connect in Redis : { self .host } " )
207
- raise IdempotencyPersistenceConnectionError ("Could not to connect to Redis " , exc ) from exc
206
+ logger .debug (f"Cannot connect to Cache endpoint : { self .host } " )
207
+ raise IdempotencyPersistenceConnectionError ("Could not to connect to Cache endpoint " , exc ) from exc
208
208
209
209
210
210
@deprecated ("RedisCachePersistenceLayer will be removed in v4.0.0. Please use CachePersistenceLayer instead." )
@@ -215,7 +215,7 @@ def __init__(
215
215
host : str = "" ,
216
216
port : int = 6379 ,
217
217
username : str = "" ,
218
- password : str = "" , # nosec - password for Redis connection
218
+ password : str = "" , # nosec - password for Cache connection
219
219
db_index : int = 0 ,
220
220
mode : Literal ["standalone" , "cluster" ] = "standalone" ,
221
221
ssl : bool = True ,
@@ -227,39 +227,39 @@ def __init__(
227
227
validation_key_attr : str = "validation" ,
228
228
):
229
229
"""
230
- Initialize the Redis Persistence Layer
230
+ Initialize the Cache Persistence Layer
231
231
232
232
Parameters
233
233
----------
234
234
host: str, optional
235
- Redis host
235
+ Cache host
236
236
port: int, optional: default 6379
237
- Redis port
237
+ Cache port
238
238
username: str, optional
239
- Redis username
239
+ Cache username
240
240
password: str, optional
241
- Redis password
241
+ Cache password
242
242
url: str, optional
243
- Redis connection string, using url will override the host/port in the previous parameters
243
+ Cache connection string, using url will override the host/port in the previous parameters
244
244
db_index: int, optional: default 0
245
- Redis db index
245
+ Cache db index
246
246
mode: str, Literal["standalone","cluster"]
247
- set Redis client mode, choose from standalone/cluster
247
+ set Cache client mode, choose from standalone/cluster
248
248
ssl: bool, optional: default True
249
- set whether to use ssl for Redis connection
250
- client: RedisClientProtocol , optional
251
- Bring your own Redis client that follows RedisClientProtocol .
249
+ set whether to use ssl for Cache connection
250
+ client: CacheClientProtocol , optional
251
+ Bring your own Cache client that follows CacheClientProtocol .
252
252
If provided, all other connection configuration options will be ignored
253
253
expiry_attr: str, optional
254
- Redis json attribute name for expiry timestamp, by default "expiration"
254
+ Cache json attribute name for expiry timestamp, by default "expiration"
255
255
in_progress_expiry_attr: str, optional
256
- Redis json attribute name for in-progress expiry timestamp, by default "in_progress_expiration"
256
+ Cache json attribute name for in-progress expiry timestamp, by default "in_progress_expiration"
257
257
status_attr: str, optional
258
- Redis json attribute name for status, by default "status"
258
+ Cache json attribute name for status, by default "status"
259
259
data_attr: str, optional
260
- Redis json attribute name for response data, by default "data"
260
+ Cache json attribute name for response data, by default "data"
261
261
validation_key_attr: str, optional
262
- Redis json attribute name for hashed representation of the parts of the event used for validation
262
+ Cache json attribute name for hashed representation of the parts of the event used for validation
263
263
264
264
Examples
265
265
--------
@@ -270,16 +270,16 @@ def __init__(
270
270
idempotent,
271
271
)
272
272
273
- from aws_lambda_powertools.utilities.idempotency.persistence.redis import (
274
- RedisCachePersistenceLayer ,
273
+ from aws_lambda_powertools.utilities.idempotency.persistence.cache import (
274
+ CachePersistenceLayer ,
275
275
)
276
276
277
277
client = redis.Redis(
278
278
host="localhost",
279
279
port="6379",
280
280
decode_responses=True,
281
281
)
282
- persistence_layer = RedisCachePersistenceLayer (client=client)
282
+ persistence_layer = CachePersistenceLayer (client=client)
283
283
284
284
@idempotent(persistence_store=persistence_layer)
285
285
def lambda_handler(event: dict, context: LambdaContext):
@@ -292,7 +292,7 @@ def lambda_handler(event: dict, context: LambdaContext):
292
292
```
293
293
"""
294
294
295
- # Initialize Redis client with Redis config if no client is passed in
295
+ # Initialize Cache client with cache config if no client is passed in
296
296
if client is None :
297
297
self .client = RedisConnection (
298
298
host = host ,
@@ -334,11 +334,11 @@ def _item_to_data_record(self, idempotency_key: str, item: dict[str, Any]) -> Da
334
334
in_progress_expiry_timestamp = in_progress_expiry_timestamp ,
335
335
response_data = str (item .get (self .data_attr )),
336
336
payload_hash = str (item .get (self .validation_key_attr )),
337
- expiry_timestamp = item .get ("expiration" , None ),
337
+ expiry_timestamp = item .get ("expiration" ),
338
338
)
339
339
340
340
def _get_record (self , idempotency_key ) -> DataRecord :
341
- # See: https://redis .io/commands/get/
341
+ # See: https://valkey .io/valkey-glide/python/core/#glide.async_commands.CoreCommands.set
342
342
response = self .client .get (idempotency_key )
343
343
344
344
# key not found
@@ -388,25 +388,25 @@ def _put_in_progress_record(self, data_record: DataRecord) -> None:
388
388
# The idempotency key does not exist:
389
389
# - first time that this invocation key is used
390
390
# - previous invocation with the same key was deleted due to TTL
391
- # - SET see https://redis .io/commands/set/
391
+ # - SET see https://valkey .io/valkey-glide/python/core/#glide.async_commands.CoreCommands.set
392
392
393
- logger .debug (f"Putting record on Redis for idempotency key: { data_record .idempotency_key } " )
393
+ logger .debug (f"Putting record on Cache for idempotency key: { data_record .idempotency_key } " )
394
394
encoded_item = self ._json_serializer (item ["mapping" ])
395
395
ttl = self ._get_expiry_second (expiry_timestamp = data_record .expiry_timestamp )
396
396
397
- redis_response = self .client .set (name = data_record .idempotency_key , value = encoded_item , ex = ttl , nx = True )
397
+ cache_response = self .client .set (name = data_record .idempotency_key , value = encoded_item , ex = ttl , nx = True )
398
398
399
- # If redis_response is True, the Redis SET operation was successful and the idempotency key was not
399
+ # If cache_response is True, the Cache SET operation was successful and the idempotency key was not
400
400
# previously set. This indicates that we can safely proceed to the handler execution phase.
401
401
# Most invocations should successfully proceed past this point.
402
- if redis_response :
402
+ if cache_response :
403
403
return
404
404
405
- # If redis_response is None, it indicates an existing record in Redis for the given idempotency key.
405
+ # If cache_response is None, it indicates an existing record in Cache for the given idempotency key.
406
406
# This could be due to:
407
407
# - An active idempotency record from a previous invocation that has not yet expired.
408
408
# - An orphan record where a previous invocation has timed out.
409
- # - An expired idempotency record that has not been deleted by Redis .
409
+ # - An expired idempotency record that has not been deleted by Cache .
410
410
# In any case, we proceed to retrieve the record for further inspection.
411
411
412
412
idempotency_record = self ._get_record (data_record .idempotency_key )
@@ -431,32 +431,30 @@ def _put_in_progress_record(self, data_record: DataRecord) -> None:
431
431
432
432
# Reaching this point indicates that the idempotency record found is an orphan record. An orphan record is
433
433
# one that is neither completed nor in-progress within its expected time frame. It may result from a
434
- # previous invocation that has timed out or an expired record that has yet to be cleaned up by Redis .
434
+ # previous invocation that has timed out or an expired record that has yet to be cleaned up by Cache .
435
435
# We raise an error to handle this exceptional scenario appropriately.
436
436
raise IdempotencyPersistenceConsistencyError
437
437
438
438
except IdempotencyPersistenceConsistencyError :
439
439
# Handle an orphan record by attempting to acquire a lock, which by default lasts for 10 seconds.
440
440
# The purpose of acquiring the lock is to prevent race conditions with other processes that might
441
441
# also be trying to handle the same orphan record. Once the lock is acquired, we set a new value
442
- # for the idempotency record in Redis with the appropriate time-to-live (TTL).
442
+ # for the idempotency record in Cache with the appropriate time-to-live (TTL).
443
443
with self ._acquire_lock (name = item ["name" ]):
444
444
self .client .set (name = item ["name" ], value = encoded_item , ex = ttl )
445
445
446
446
# Not removing the lock here serves as a safeguard against race conditions,
447
447
# preventing another operation from mistakenly treating this record as an orphan while the
448
448
# current operation is still in progress.
449
- except (redis .exceptions .RedisError , redis .exceptions .RedisClusterException ) as e :
450
- raise e
451
449
except Exception as e :
452
- logger .debug (f"encountered non-Redis exception : { e } " )
453
- raise e
450
+ logger .debug (f"An error occurred : { e } " )
451
+ raise
454
452
455
453
@contextmanager
456
454
def _acquire_lock (self , name : str ):
457
455
"""
458
456
Attempt to acquire a lock for a specified resource name, with a default timeout.
459
- This context manager attempts to set a lock using Redis to prevent concurrent
457
+ This context manager attempts to set a lock using Cache to prevent concurrent
460
458
access to a resource identified by 'name'. It uses the 'nx' flag to ensure that
461
459
the lock is only set if it does not already exist, thereby enforcing mutual exclusion.
462
460
"""
@@ -500,15 +498,20 @@ def _update_record(self, data_record: DataRecord) -> None:
500
498
501
499
def _delete_record (self , data_record : DataRecord ) -> None :
502
500
"""
503
- Deletes the idempotency record associated with a given DataRecord from Redis .
501
+ Deletes the idempotency record associated with a given DataRecord from Cache .
504
502
This function is designed to be called after a Lambda handler invocation has completed processing.
505
- It ensures that the idempotency key associated with the DataRecord is removed from Redis to
503
+ It ensures that the idempotency key associated with the DataRecord is removed from Cache to
506
504
prevent future conflicts and to maintain the idempotency integrity.
507
505
508
506
Note: it is essential that the idempotency key is not empty, as that would indicate the Lambda
509
507
handler has not been invoked or the key was not properly set.
510
508
"""
511
509
logger .debug (f"Deleting record for idempotency key: { data_record .idempotency_key } " )
512
510
513
- # See: https://redis .io/commands/del/
511
+ # See: https://valkey .io/valkey-glide/python/core/#glide.async_commands.CoreCommands.delete
514
512
self .client .delete (data_record .idempotency_key )
513
+
514
+
515
+ CachePersistenceLayer : TypeAlias = RedisCachePersistenceLayer
516
+ CacheClientProtocol : TypeAlias = RedisClientProtocol
517
+ CacheConnection : TypeAlias = RedisConnection
0 commit comments