@@ -400,6 +400,54 @@ public function restoreLock($name, $owner)
400400 return $ this ->lock ($ name , 0 , $ owner );
401401 }
402402
403+ /**
404+ * Atomically refresh the expiration of a key if it matches the expected owner.
405+ *
406+ * @param string $key
407+ * @param mixed $expectedOwner
408+ * @param int $seconds
409+ * @return bool
410+ */
411+ public function refreshIfOwned ($ key , $ expectedOwner , $ seconds )
412+ {
413+ try {
414+ $ this ->dynamo ->updateItem ([
415+ 'TableName ' => $ this ->table ,
416+ 'Key ' => [
417+ $ this ->keyAttribute => [
418+ 'S ' => $ this ->prefix .$ key ,
419+ ],
420+ ],
421+ 'ConditionExpression ' => 'attribute_exists(#key) AND #value = :owner AND #expires_at > :now ' ,
422+ 'UpdateExpression ' => 'SET #expires_at = :expires_at ' ,
423+ 'ExpressionAttributeNames ' => [
424+ '#key ' => $ this ->keyAttribute ,
425+ '#value ' => $ this ->valueAttribute ,
426+ '#expires_at ' => $ this ->expirationAttribute ,
427+ ],
428+ 'ExpressionAttributeValues ' => [
429+ ':owner ' => [
430+ $ this ->type ($ expectedOwner ) => $ this ->serialize ($ expectedOwner ),
431+ ],
432+ ':now ' => [
433+ 'N ' => (string ) $ this ->currentTime (),
434+ ],
435+ ':expires_at ' => [
436+ 'N ' => (string ) $ this ->toTimestamp ($ seconds ),
437+ ],
438+ ],
439+ ]);
440+
441+ return true ;
442+ } catch (DynamoDbException $ e ) {
443+ if (str_contains ($ e ->getMessage (), 'ConditionalCheckFailed ' )) {
444+ return false ;
445+ }
446+
447+ throw $ e ;
448+ }
449+ }
450+
403451 /**
404452 * Remove an item from the cache.
405453 *
0 commit comments