Coverage for api/utils/dead_link_mask.py: 84%
31 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 06:14 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 06:14 +0000
1import django_redis
2import structlog
3from deepdiff import DeepHash
4from elasticsearch_dsl import Search
5from redis.exceptions import ConnectionError
8logger = structlog.get_logger(__name__)
11# 3 hours minutes (in seconds)
12DEAD_LINK_MASK_TTL = 60 * 60 * 3
15def get_query_hash(s: Search) -> str:
16 """
17 Hash the search query using a deterministic algorithm.
19 Generates a deterministic Murmur3 or SHA256 hash from the serialized Search
20 object using DeepHash so that two Search objects with the same content will
21 produce the same hash.
23 :param s: Search object to be serialized and hashed.
24 :return: Serialized Search object hash.
25 """
26 serialized_search_obj = s.to_dict()
27 serialized_search_obj.pop("from", None)
28 serialized_search_obj.pop("size", None)
29 deep_hash = DeepHash(serialized_search_obj)[serialized_search_obj]
30 return deep_hash
33def get_query_mask(query_hash: str) -> list[int]:
34 """
35 Fetch an existing query mask for a given query hash or returns an empty one.
37 :param query_hash: Unique value for a particular query.
38 :return: Boolean mask as a list of integers (0 or 1).
39 """
40 redis = django_redis.get_redis_connection("default")
41 key = f"{query_hash}:dead_link_mask"
42 try:
43 return list(map(int, redis.lrange(key, 0, -1)))
44 except ConnectionError:
45 logger.warning("Redis connect failed, cannot get cached query mask.")
46 return []
49def save_query_mask(query_hash: str, mask: list):
50 """
51 Save a query mask to redis.
53 :param mask: Boolean mask as a list of integers (0 or 1).
54 :param query_hash: Unique value to be used as key.
55 """
56 redis_pipe = django_redis.get_redis_connection("default").pipeline()
57 key = f"{query_hash}:dead_link_mask"
59 redis_pipe.delete(key)
60 redis_pipe.rpush(key, *mask)
61 redis_pipe.expire(key, DEAD_LINK_MASK_TTL)
63 try:
64 redis_pipe.execute()
65 except ConnectionError:
66 logger.warning("Redis connect failed, cannot cache query mask.")