Coverage for src / lexigram / contracts / infra / cache / protocols.py: 0%

29 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-15 18:57 +0800

1"""Cache protocol class definitions. 

2 

3Protocol classes for caching backends and related utilities. 

4""" 

5 

6from __future__ import annotations 

7 

8from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable 

9 

10from lexigram.contracts.core import HealthCheckResult, ProviderProtocol 

11 

12if TYPE_CHECKING: 

13 from collections.abc import Callable 

14 

15 from lexigram.contracts.core.result import Result 

16 from lexigram.contracts.infra.cache.exceptions import CacheError 

17 

18 

19@runtime_checkable 

20class CacheBackendProtocol(Protocol): 

21 """Protocol for cache backend implementations. 

22 

23 This interface defines the contract that all cache backend implementations 

24 must follow. It provides a unified API for different storage mechanisms 

25 (memory, Redis, Memcached, etc.). 

26 

27 Example: 

28 ```python 

29 class RedisBackend: 

30 async def get(self, key: str) -> Result[Any | None, CacheError]: 

31 try: 

32 data = await self._redis.get(key) 

33 return Ok(self._serializer.deserialize(data) if data else None) 

34 except Exception as exc: 

35 return Err(CacheError(str(exc))) 

36 

37 async def set( 

38 self, key: str, value: Any, ttl: int | None = None 

39 ) -> Result[None, CacheError]: 

40 try: 

41 data = self._serializer.serialize(value) 

42 await self._redis.set(key, data, ex=ttl) 

43 return Ok(None) 

44 except Exception as exc: 

45 return Err(CacheError(str(exc))) 

46 ``` 

47 """ 

48 

49 async def get(self, key: str) -> Result[Any | None, CacheError]: 

50 """Get a value from the cache. 

51 

52 Args: 

53 key: The cache key to retrieve. 

54 

55 Returns: 

56 Ok(value) if found, Ok(None) if not found, Err(CacheError) on failure. 

57 

58 Note: 

59 The return type is ``Any`` by design: the cache is a 

60 heterogeneous store and the caller knows the expected type. 

61 Use ``cast(T, result.unwrap())`` at call sites for type safety. 

62 """ 

63 ... 

64 

65 async def set( 

66 self, key: str, value: Any, ttl: int | None = None 

67 ) -> Result[None, CacheError]: 

68 """Set a value in the cache with optional TTL. 

69 

70 Args: 

71 key: The cache key to set. 

72 value: The value to cache. 

73 ttl: Time to live in seconds (optional). 

74 

75 Returns: 

76 Ok(None) if successful, Err(CacheError) on failure. 

77 """ 

78 ... 

79 

80 async def delete(self, key: str) -> Result[bool, CacheError]: 

81 """Delete a value from the cache. 

82 

83 Args: 

84 key: The cache key to delete. 

85 

86 Returns: 

87 Ok(True) if deleted, Ok(False) if not found, Err(CacheError) on failure. 

88 """ 

89 ... 

90 

91 async def delete_many(self, keys: list[str]) -> Result[int, CacheError]: 

92 """Delete multiple values from the cache. 

93 

94 Args: 

95 keys: List of cache keys to delete. 

96 

97 Returns: 

98 Ok(count) of deleted keys, Err(CacheError) on failure. 

99 """ 

100 ... 

101 

102 async def delete_pattern(self, pattern: str) -> Result[int, CacheError]: 

103 """Delete all keys matching a glob-style pattern. 

104 

105 Args: 

106 pattern: Glob pattern (e.g. ``"pet:list:*"``). Supports ``*`` 

107 as a wildcard matching any sequence of characters. 

108 

109 Returns: 

110 Ok(count) of deleted keys, Err(CacheError) on failure. 

111 """ 

112 ... 

113 

114 async def exists(self, key: str) -> Result[bool, CacheError]: 

115 """Check if a key exists in the cache. 

116 

117 Args: 

118 key: The cache key to check. 

119 

120 Returns: 

121 Ok(True) if exists, Ok(False) otherwise, Err(CacheError) on failure. 

122 """ 

123 ... 

124 

125 async def clear(self) -> Result[None, CacheError]: 

126 """Clear all values from the cache. 

127 

128 Returns: 

129 Ok(None) if successful, Err(CacheError) on failure. 

130 """ 

131 ... 

132 

133 async def get_many(self, keys: list[str]) -> Result[dict[str, Any], CacheError]: 

134 """Get multiple values from the cache. 

135 

136 Args: 

137 keys: List of cache keys to retrieve. 

138 

139 Returns: 

140 Ok(dict) mapping found keys to values, Err(CacheError) on failure. 

141 """ 

142 ... 

143 

144 async def set_many( 

145 self, items: dict[str, Any], ttl: int | None = None 

146 ) -> Result[None, CacheError]: 

147 """Set multiple values in the cache. 

148 

149 Args: 

150 items: Dictionary of key-value pairs to cache. 

151 ttl: Time to live in seconds for all items. 

152 

153 Returns: 

154 Ok(None) if all items set successfully, Err(CacheError) on failure. 

155 """ 

156 ... 

157 

158 async def health_check(self, timeout: float = 5.0) -> HealthCheckResult: 

159 """Perform a health check on the cache backend. 

160 

161 Returns: 

162 Structured HealthCheckResult. 

163 """ 

164 ... 

165 

166 

167@runtime_checkable 

168class CacheProtectionStrategyProtocol(Protocol): 

169 """Protocol for cache stampede protection strategies.""" 

170 

171 async def acquire_lock(self, key: str, ttl: int) -> bool: 

172 """Attempt to acquire a lock for cache population. 

173 

174 Args: 

175 key: Cache key to lock. 

176 ttl: Lock TTL in seconds. 

177 

178 Returns: 

179 True if lock was acquired. 

180 """ 

181 ... 

182 

183 async def release_lock(self, key: str) -> bool: 

184 """Release a previously acquired lock. 

185 

186 Args: 

187 key: Cache key to unlock. 

188 

189 Returns: 

190 True if released successfully. 

191 """ 

192 ... 

193 

194 async def wait_for_value( 

195 self, 

196 key: str, 

197 timeout: float, 

198 check_interval: float = 0.1, 

199 ) -> Any | None: 

200 """Wait for a value to be populated. 

201 

202 Args: 

203 key: Cache key to wait for. 

204 timeout: Maximum wait time in seconds. 

205 check_interval: Check interval in seconds. 

206 

207 Returns: 

208 Cached value if found, None if timeout. 

209 """ 

210 ... 

211 

212 

213@runtime_checkable 

214class CacheKeyBuilderProtocol(Protocol): 

215 """Protocol for building cache keys from function arguments.""" 

216 

217 def build_key( 

218 self, 

219 func: Callable[..., Any], 

220 args: tuple[Any, ...], 

221 kwargs: dict[str, Any], 

222 prefix: str | None = None, 

223 ) -> str: 

224 """Build a cache key from function call information. 

225 

226 Args: 

227 func: Function being cached. 

228 args: Positional arguments. 

229 kwargs: Keyword arguments. 

230 prefix: Optional key prefix. 

231 

232 Returns: 

233 Unique cache key string. 

234 """ 

235 ... 

236 

237 

238@runtime_checkable 

239class CacheHealthCheckerProtocol(Protocol): 

240 """Protocol for cache health checking.""" 

241 

242 async def health_check(self, timeout: float = 5.0) -> HealthCheckResult: 

243 """Perform a health check on the cache. 

244 

245 Returns: 

246 Structured HealthCheckResult. 

247 """ 

248 ... 

249 

250 

251@runtime_checkable 

252class CacheProviderProtocol(ProviderProtocol, Protocol): 

253 """Protocol for cache providers. 

254 

255 Cache providers are responsible for setting up caching backends, 

256 cache warming, and cache management. 

257 """ 

258 

259 

260__all__ = [ 

261 "CacheBackendProtocol", 

262 "CacheHealthCheckerProtocol", 

263 "CacheKeyBuilderProtocol", 

264 "CacheProtectionStrategyProtocol", 

265 "CacheProviderProtocol", 

266]