2b5a7b09eb9ba409673ed98b38d47c1c15f5f040
chongming-cache
统一缓存封装,dict-like 接口,后端可切换 diskcache / redis,通过配置一行切换,业务代码零改动。
安装
uv pip install -e utils/cache
# 或作为依赖接入(与 chongming-database 等同约定):
# [tool.uv.sources]
# chongming-cache = { git = "http://124.71.68.6:3000/chongming/chongming-utils-cache.git" }
快速开始
from chongming_cache import Cache
# 方式一:从配置创建(主项目 config.toml 的 [cache] 段)
cache = Cache.from_config(config["cache"])
# 方式二:显式参数
cache = Cache("diskcache", cache_store_path="./cache_data")
# cache = Cache("redis", redis_host="127.0.0.1", redis_port=6379, redis_prefix="chongming:")
映射协议(与 diskcache 用法一致)
cache["key"] = {"a": 1} # 写入(无 TTL)
if "key" in cache: # 存在性检查(含 TTL 判断)
value = cache["key"] # 读取,未命中抛 KeyError
del cache["key"] # 删除,未命中抛 KeyError
len(cache) # 条目数
for k in cache: ... # 迭代 key
扩展接口
cache.get("key", default=None) # 未命中返回 default
cache.set("key", value, expire=60) # 写入,TTL 秒(None = 永久)
cache.touch("key", expire=120) # 刷新 TTL,返回是否命中(未命中 False)
cache.delete("key") # 删除,返回是否命中
cache.clear() # 清空(redis 仅清本前缀命名空间)
cache.close() # 释放连接
with Cache.from_config(cfg) as cache: ... # 上下文管理器,退出自动 close
cache.client # 底层客户端逃生口(diskcache.Cache / redis.Redis)
# 原子写(分布式锁原语):仅当 key 不存在时写入,成功返回 True,已存在返回 False,不覆盖
ok = cache.backend.set_nx("leader", {"node": "gw-1"}, expire=30)
分布式排他锁 DistributedLock
基于 backend.set_nx(SET NX + TTL 租约)实现的跨进程/跨主机排他锁,用于集群协调(如保证全局只有一个 MQTT Bridge 消费):
import asyncio
from chongming_cache import Cache, DistributedLock
async def main():
cache = Cache.from_config(config["cache"])
lock = DistributedLock(cache, "mqtt_bridge", ttl=30, renew_interval=10)
if not lock.acquire(): # 全局唯一持锁方返回 True,其余返回 False
print("其他实例已持有,跳过")
return
lock.start() # 后台自动续约(防宕机/长暂停导致锁过期被抢)
try:
... # 执行受保护的单例任务
finally:
await lock.stop() # 停止续约
lock.release() # 受保护释放
cache.close()
asyncio.run(main())
acquire():SET NX,原子地仅在不存在时写入;key 带 TTL 租约,持有方宕机后到期自动让出,不会死锁。start()/stop():后台续约任务;续约前校验 token,仅在自己仍持有时touch,锁丢失即停止续约。release():受保护释放——仅当 token 仍匹配(仍是自己持有)才删除,绝不误删其他进程/主机抢到的锁。- 后端适用性:
redis真正跨主机共享;diskcache进程安全(SQLite),可用于单机多进程或共享卷场景,不可跨无共享文件系统的主机。
后端配置(config.toml [cache] 段)
[cache]
backend = "diskcache" # "diskcache"(默认) | "redis"
cache_store_path = "./cache_data"
# redis 后端专用(backend = "redis" 时生效,均有默认值)
# redis_host = "127.0.0.1"
# redis_port = 6379
# redis_db = 0
# redis_password = ""
# redis_prefix = "chongming:"
所有键均可缺省:旧配置(只有 cache_store_path)自动按 diskcache 后端工作。
双后端语义对齐
| 行为 | diskcache | redis |
|---|---|---|
| 值序列化 | pickle | pickle(保持任意 Python 对象语义一致) |
未命中 cache[key] |
KeyError |
KeyError |
set(..., expire=N) |
秒级 TTL,读时惰性淘汰 | SET EX N,到期即消失 |
touch(未命中) |
返回 False | 返回 False |
clear() |
清空本地缓存 | 仅清 redis_prefix 命名空间(不 flushdb) |
| 多进程安全 | 是(SQLite + 锁) | 是(服务端原子性) |
依赖
diskcache— 本地持久化后端redis— 远程后端(懒加载,diskcache-only 打包产物不引入)
Languages
Python
100%