@@ -244,19 +244,12 @@ async def _apply_ttl_to_keys(
244244 pipeline = self ._redis .pipeline (transaction = True )
245245
246246 # Set TTL for main key
247- # Use MagicMock in tests to avoid coroutine warning
248- expire_result = pipeline .expire (main_key , ttl_seconds )
249- # If expire returns a coroutine (in tests), await it
250- if hasattr (expire_result , "__await__" ):
251- await expire_result
247+ pipeline .expire (main_key , ttl_seconds )
252248
253249 # Set TTL for related keys
254250 if related_keys : # Check if related_keys is not None
255251 for key in related_keys :
256- expire_result = pipeline .expire (key , ttl_seconds )
257- # If expire returns a coroutine (in tests), await it
258- if hasattr (expire_result , "__await__" ):
259- await expire_result
252+ pipeline .expire (key , ttl_seconds )
260253
261254 await pipeline .execute ()
262255
@@ -739,50 +732,43 @@ async def _batch_search_ops(
739732 result_map = {}
740733
741734 if self .cluster_mode :
742- store_docs_list = []
743- for (
744- doc_vr
745- ) in (
746- vector_results_docs
747- ): # doc_vr is now an individual doc from the list
748- doc_id_vr = (
749- doc_vr .get ("id" )
750- if isinstance (doc_vr , dict )
751- else getattr (doc_vr , "id" , None )
735+ store_docs = []
736+ for doc in vector_results_docs :
737+ doc_id = (
738+ doc .get ("id" )
739+ if isinstance (doc , dict )
740+ else getattr (doc , "id" , None )
752741 )
753- if doc_id_vr :
754- doc_uuid_vr = doc_id_vr .split (":" )[1 ]
755- store_key_vr = (
756- f"{ STORE_PREFIX } { REDIS_KEY_SEPARATOR } { doc_uuid_vr } "
757- )
758- result_map [store_key_vr ] = doc_vr
742+ if doc_id :
743+ doc_uuid = doc_id .split (":" )[1 ]
744+ store_key = f"{ STORE_PREFIX } { REDIS_KEY_SEPARATOR } { doc_uuid } "
745+ result_map [store_key ] = doc
759746 # Fetch individually in cluster mode
760- store_doc_item = await self ._redis .json ().get (store_key_vr )
761- store_docs_list .append (store_doc_item )
762- store_docs_raw = store_docs_list
747+ store_doc_item = await self ._redis .json ().get (store_key )
748+ store_docs .append (store_doc_item )
749+ store_docs_raw = store_docs
763750 else :
764751 pipeline = self ._redis .pipeline (transaction = False )
765752 for (
766- doc_vr
753+ doc
767754 ) in (
768755 vector_results_docs
769756 ): # doc_vr is now an individual doc from the list
770- doc_id_vr = (
771- doc_vr .get ("id" )
772- if isinstance (doc_vr , dict )
773- else getattr (doc_vr , "id" , None )
757+ doc_id = (
758+ doc .get ("id" )
759+ if isinstance (doc , dict )
760+ else getattr (doc , "id" , None )
774761 )
775- if doc_id_vr :
776- doc_uuid_vr = doc_id_vr .split (":" )[1 ]
777- store_key_vr = (
778- f"{ STORE_PREFIX } { REDIS_KEY_SEPARATOR } { doc_uuid_vr } "
779- )
780- result_map [store_key_vr ] = doc_vr
781- pipeline .json ().get (store_key_vr )
762+ if doc_id :
763+ doc_uuid = doc_id .split (":" )[1 ]
764+ store_key = f"{ STORE_PREFIX } { REDIS_KEY_SEPARATOR } { doc_uuid } "
765+ result_map [store_key ] = doc
766+ pipeline .json ().get (store_key )
782767 store_docs_raw = await pipeline .execute ()
783768
784769 # Process results maintaining order and applying filters
785770 items = []
771+ refresh_keys = [] # Track keys that need TTL refreshed
786772 store_docs_iter = iter (store_docs_raw )
787773
788774 for store_key in result_map .keys ():
@@ -834,13 +820,48 @@ async def _batch_search_ops(
834820 if not matches :
835821 continue
836822
823+ # If refresh_ttl is true, add to list for refreshing
824+ if op .refresh_ttl :
825+ refresh_keys .append (store_key )
826+ # Also find associated vector keys with same ID
827+ doc_id = store_key .split (":" )[- 1 ]
828+ vector_key = (
829+ f"{ STORE_VECTOR_PREFIX } { REDIS_KEY_SEPARATOR } { doc_id } "
830+ )
831+ refresh_keys .append (vector_key )
832+
837833 items .append (
838834 _row_to_search_item (
839835 _decode_ns (store_doc ["prefix" ]),
840836 store_doc ,
841837 score = score ,
842838 )
843839 )
840+
841+ # Refresh TTL if requested
842+ if op .refresh_ttl and refresh_keys and self .ttl_config :
843+ # Get default TTL from config
844+ ttl_minutes = None
845+ if "default_ttl" in self .ttl_config :
846+ ttl_minutes = self .ttl_config .get ("default_ttl" )
847+
848+ if ttl_minutes is not None :
849+ ttl_seconds = int (ttl_minutes * 60 )
850+ if self .cluster_mode :
851+ for key in refresh_keys :
852+ ttl = await self ._redis .ttl (key )
853+ if ttl > 0 :
854+ await self ._redis .expire (key , ttl_seconds )
855+ else :
856+ pipeline = self ._redis .pipeline (transaction = True )
857+ for key in refresh_keys :
858+ # Only refresh TTL if the key exists and has a TTL
859+ ttl = await self ._redis .ttl (key )
860+ if ttl > 0 : # Only refresh if key exists and has TTL
861+ pipeline .expire (key , ttl_seconds )
862+ if pipeline .command_stack :
863+ await pipeline .execute ()
864+
844865 results [idx ] = items
845866
846867 else :
@@ -851,6 +872,7 @@ async def _batch_search_ops(
851872 # Execute search with limit and offset applied by Redis
852873 res = await self .store_index .search (query )
853874 items = []
875+ refresh_keys = [] # Track keys that need TTL refreshed
854876
855877 for doc in res .docs :
856878 data = json .loads (doc .json )
@@ -869,7 +891,43 @@ async def _batch_search_ops(
869891 break
870892 if not matches :
871893 continue
894+
895+ # If refresh_ttl is true, add the key to refresh list
896+ if op .refresh_ttl :
897+ refresh_keys .append (doc .id )
898+ # Also find associated vector keys with same ID
899+ doc_id = doc .id .split (":" )[- 1 ]
900+ vector_key = (
901+ f"{ STORE_VECTOR_PREFIX } { REDIS_KEY_SEPARATOR } { doc_id } "
902+ )
903+ refresh_keys .append (vector_key )
904+
872905 items .append (_row_to_search_item (_decode_ns (data ["prefix" ]), data ))
906+
907+ # Refresh TTL if requested
908+ if op .refresh_ttl and refresh_keys and self .ttl_config :
909+ # Get default TTL from config
910+ ttl_minutes = None
911+ if "default_ttl" in self .ttl_config :
912+ ttl_minutes = self .ttl_config .get ("default_ttl" )
913+
914+ if ttl_minutes is not None :
915+ ttl_seconds = int (ttl_minutes * 60 )
916+ if self .cluster_mode :
917+ for key in refresh_keys :
918+ ttl = await self ._redis .ttl (key )
919+ if ttl > 0 :
920+ await self ._redis .expire (key , ttl_seconds )
921+ else :
922+ pipeline = self ._redis .pipeline (transaction = True )
923+ for key in refresh_keys :
924+ # Only refresh TTL if the key exists and has a TTL
925+ ttl = await self ._redis .ttl (key )
926+ if ttl > 0 : # Only refresh if key exists and has TTL
927+ pipeline .expire (key , ttl_seconds )
928+ if pipeline .command_stack :
929+ await pipeline .execute ()
930+
873931 results [idx ] = items
874932
875933 async def _batch_list_namespaces_ops (
0 commit comments