cache.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import json
  2. import logging
  3. from typing import Any, Optional, List
  4. from datetime import datetime
  5. from app.core.config import redis_client
  6. logger = logging.getLogger(__name__)
  7. class DateTimeEncoder(json.JSONEncoder):
  8. def default(self, obj):
  9. if isinstance(obj, datetime):
  10. return obj.isoformat()
  11. return super().default(obj)
  12. class RedisService:
  13. """Redis 缓存与缓冲服务类"""
  14. @staticmethod
  15. def set_cache(key: str, value: Any, expire: int = 3600):
  16. """通用缓存写入"""
  17. if not redis_client: return False
  18. try:
  19. redis_client.set(key, json.dumps(value, cls=DateTimeEncoder), ex=expire)
  20. return True
  21. except Exception as e:
  22. logger.error(f"Redis 缓存设置失败: {e}")
  23. return False
  24. @staticmethod
  25. def get_cache(key: str) -> Optional[Any]:
  26. """通用缓存读取"""
  27. if not redis_client: return None
  28. try:
  29. data = redis_client.get(key)
  30. return json.loads(data) if data else None
  31. except Exception as e:
  32. logger.error(f"Redis 缓存读取失败: {e}")
  33. return None
  34. @staticmethod
  35. def delete_cache(key: str) -> bool:
  36. """删除单个缓存"""
  37. if not redis_client: return False
  38. try:
  39. redis_client.delete(key)
  40. return True
  41. except Exception as e:
  42. logger.error(f"Redis 缓存删除失败: {e}")
  43. return False
  44. @staticmethod
  45. def delete_keys_pattern(pattern: str) -> int:
  46. """按模式批量删除缓存"""
  47. if not redis_client: return 0
  48. try:
  49. # Use scan_iter for robust cursor handling
  50. keys = list(redis_client.scan_iter(match=pattern, count=100))
  51. if keys:
  52. logger.info(f"Deleting {len(keys)} keys matching pattern '{pattern}'")
  53. return redis_client.delete(*keys)
  54. return 0
  55. except Exception as e:
  56. logger.error(f"Redis 模式删除失败: {e}")
  57. return 0
  58. @staticmethod
  59. def push_message(queue: str, message: Any):
  60. """消息缓冲:将数据推入队列尾部 (用于日志或消息缓冲)"""
  61. if not redis_client: return False
  62. try:
  63. redis_client.rpush(queue, json.dumps(message, cls=DateTimeEncoder))
  64. return True
  65. except Exception as e:
  66. logger.error(f"Redis 消息缓冲推送失败: {e}")
  67. return False
  68. @staticmethod
  69. def pop_messages(queue: str, count: int = 10) -> List[Any]:
  70. """批量获取并移除缓冲的消息 (用于批量写入数据库)"""
  71. if not redis_client: return []
  72. messages = []
  73. try:
  74. # 循环弹出指定数量的消息
  75. for _ in range(count):
  76. msg = redis_client.lpop(queue)
  77. if not msg: break
  78. messages.append(json.loads(msg))
  79. return messages
  80. except Exception as e:
  81. logger.error(f"Redis 消息弹出失败: {e}")
  82. return []
  83. cache_service = RedisService()