File size: 3,938 Bytes
f202266
 
ab7ee83
f202266
 
 
 
 
 
ccbdc68
f202266
 
ccbdc68
f202266
 
 
 
 
ab7ee83
 
 
 
f202266
ab7ee83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f202266
 
 
 
 
 
 
ab7ee83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f202266
 
 
 
ccbdc68
f202266
 
 
ab7ee83
 
 
 
 
f202266
 
 
 
 
ab7ee83
f202266
 
 
ab7ee83
f202266
 
 
 
 
 
 
 
 
 
ccbdc68
ab7ee83
f202266
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import json
from functools import wraps
from services.config.valkey_config import get_redis_client, is_connection_available
import time

redis_client = get_redis_client()

def cache_data(key_prefix, expire_time=3600):
    """
    A decorator that caches the result of a function in Valkey.
    
    Args:
        key_prefix (str): Prefix for the Valkey key
        expire_time (int): Time in seconds for the cache to expire (default: 1 hour)
    """
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            # If Valkey is not available, execute function directly
            if not is_connection_available() or not redis_client:
                print(f"Cache DISABLED for {key_prefix} - executing function directly")
                return await func(*args, **kwargs)
            
            try:
                # Create a unique key based on the function arguments
                cache_key = f"{key_prefix}:{str(args)}:{str(kwargs)}"
                
                # Try to get the cached result
                cached_result = redis_client.get(cache_key)
                if cached_result:
                    print(f"Cache HIT: {cache_key}")
                    return json.loads(cached_result)
                
                # If not cached, execute the function
                print(f"Cache MISS: {cache_key}")
                result = await func(*args, **kwargs)
                
                # Cache the result
                redis_client.setex(
                    cache_key,
                    expire_time,
                    json.dumps(result)
                )
                
                return result
            except Exception as e:
                print(f"Cache ERROR for {key_prefix}: {e}")
                print("Falling back to direct function execution")
                return await func(*args, **kwargs)
        return wrapper
    return decorator

def clear_cache(pattern="*"):
    """
    Clear cache entries matching the given pattern
    """
    if not is_connection_available() or not redis_client:
        print("Cache DISABLED: Cannot clear cache")
        return
    
    try:
        cursor = 0
        while True:
            cursor, keys = redis_client.scan(cursor, match=pattern)
            if keys:
                redis_client.delete(*keys)
            if cursor == 0:
                break
        print(f"Cache cleared for pattern: {pattern}")
    except Exception as e:
        print(f"Cache clear ERROR: {e}")

def cache_with_fallback(func):
    """
    A decorator that implements cache with fallback mechanism
    If Valkey is unavailable, it will execute the function directly
    """
    @wraps(func)
    async def wrapper(*args, **kwargs):
        # If Valkey is not available, execute function directly
        if not is_connection_available() or not redis_client:
            print(f"Cache DISABLED for {func.__name__} - executing function directly")
            return await func(*args, **kwargs)
        
        cache_key = f"{func.__name__}:{str(args)}:{str(kwargs)}"
        try:
            # Try to get from cache
            cached_result = redis_client.get(cache_key)
            if cached_result:
                print(f"Cache HIT: {cache_key}")
                return json.loads(cached_result)
            
            # If not in cache, execute function
            print(f"Cache MISS: {cache_key}")
            result = await func(*args, **kwargs)
            
            # Cache the result
            redis_client.setex(
                cache_key,
                3600,  # 1 hour default
                json.dumps(result)
            )
            return result
        except Exception as e:
            # If Valkey fails, execute function directly
            print(f"Cache error for {func.__name__}: {str(e)}, executing function directly")
            return await func(*args, **kwargs)
    return wrapper