From 8e1d336250ab9528bb35e9fd875f5de9011279b1 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Thu, 21 Aug 2025 16:06:23 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E7=BB=9F=E4=B8=80=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/README.md b/README.md index 36b049c..5303ed0 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ MoviePilot官方插件市场:https://github.com/jxxghp/MoviePilot-Plugins - [12. 如何通过插件扩展支持的存储类型?](#12-如何通过插件扩展支持的存储类型) - [13. 如何将插件功能集成到工作流?](#13-如何将插件功能集成到工作流) - [14. 如何在插件中通过消息持续与用户交互?](#14-如何在插件中通过消息持续与用户交互) + - [15. 如何在插件中使用系统级统一缓存?](#15-如何在插件中使用系统级统一缓存) - [版本发布](#版本发布) - [1. 如何发布插件版本?](#1-如何发布插件版本) - [2. 如何开发V2版本的插件以及实现插件多版本兼容?](#2-如何开发v2版本的插件以及实现插件多版本兼容) @@ -1167,6 +1168,190 @@ def get_actions(self) -> List[Dict[str, Any]]: - 建议在交互中保存用户状态数据,以支持复杂的多步骤操作 - 可以结合插件数据存储功能保存用户的交互历史和偏好设置 +### 15. 如何在插件中使用系统级统一缓存? +**(仅支持 `v2.7.4+` 版本)** +- MoviePilot提供了统一的缓存系统,支持内存缓存、文件系统缓存和Redis缓存自动管理,当有Redis时优先使用Redis,否则使用内存或文件系统。插件可以通过系统提供的缓存接口实现高效的缓存管理,无需关心系统设置。 + +- 1. 使用缓存装饰器: + ```python + from app.core.cache import cached + + class MyPlugin(_PluginBase): + @cached(region="my_plugin", ttl=3600) + def get_data(self, key: str): + """ + 使用缓存装饰器,缓存结果1小时 + """ + # 复杂的计算或网络请求 + return expensive_operation(key) + + @cached(region="my_plugin_async", ttl=1800, skip_none=True) + async def get_async_data(self, key: str): + """ + 异步函数缓存,跳过None值 + """ + return await async_expensive_operation(key) + ``` + +- 2. 使用TTLCache类: + ```python + from app.core.cache import TTLCache + + class MyPlugin(_PluginBase): + def __init__(self): + super().__init__() + # 创建缓存实例,最大128项,TTL 30分钟 + self.cache = TTLCache(region="my_plugin", maxsize=128, ttl=1800) + + def process_data(self, key: str): + # 检查缓存 + if key in self.cache: + return self.cache[key] + + # 计算并缓存结果 + result = expensive_operation(key) + self.cache[key] = result + return result + + def clear_cache(self): + """ + 清理插件缓存 + """ + self.cache.clear() + ``` + +- 3. 使用文件缓存后端(适用于大文件缓存): + ```python + from app.core.cache import FileCache, AsyncFileCache + from pathlib import Path + + class MyPlugin(_PluginBase): + def __init__(self): + super().__init__() + # 获取文件缓存后端,支持Redis和文件系统 + self.file_cache = FileCache( + base=Path("/tmp/my_plugin_cache"), + ttl=86400 # 24小时 + ) + + def cache_large_file(self, key: str, data: bytes): + """ + 缓存大文件数据 + """ + self.file_cache.set(key, data, region="large_files") + + def get_cached_file(self, key: str) -> Optional[bytes]: + """ + 获取缓存的文件数据 + """ + return self.file_cache.get(key, region="large_files") + + async def async_cache_operations(self): + """ + 异步文件缓存操作 + """ + async_cache = AsyncFileCache( + base=Path("/tmp/my_plugin_async_cache"), + ttl=3600 + ) + + # 异步设置缓存 + await async_cache.set("async_key", b"async_data", region="async_files") + + # 异步获取缓存 + data = await async_cache.get("async_key", region="async_files") + + await async_cache.close() + ``` + +- 4. 直接使用缓存后端(高级用法): + ```python + from app.core.cache import Cache + + class MyPlugin(_PluginBase): + def __init__(self): + super().__init__() + # 直接获取缓存后端实例,系统自动选择Redis或内存缓存 + self.cache_backend = Cache(maxsize=256, ttl=3600) + + def custom_cache_operation(self, key: str, value: Any): + """ + 自定义缓存操作 + """ + # 设置缓存 + self.cache_backend.set(key, value, region="custom_region") + + # 检查缓存是否存在 + if self.cache_backend.exists(key, region="custom_region"): + # 获取缓存 + cached_value = self.cache_backend.get(key, region="custom_region") + return cached_value + + return None + + def iterate_cache_items(self): + """ + 遍历缓存项 + """ + for key, value in self.cache_backend.items(region="custom_region"): + print(f"缓存键: {key}, 值: {value}") + + def cleanup(self): + """ + 清理缓存 + """ + self.cache_backend.clear(region="custom_region") + self.cache_backend.close() + ``` + +- 5. 缓存装饰器参数说明: + ```python + @cached( + region="my_plugin", # 缓存区域,用于隔离不同插件的缓存 + maxsize=512, # 最大缓存条目数(仅内存缓存有效) + ttl=1800, # 缓存存活时间(秒) + skip_none=True, # 是否跳过None值缓存 + skip_empty=False # 是否跳过空值缓存(空列表、空字典等) + ) + def my_function(self, param): + pass + ``` + +- 6. 缓存管理功能: + ```python + class MyPlugin(_PluginBase): + @cached(region="my_plugin") + def cached_function(self, param): + return expensive_operation(param) + + def clear_my_cache(self): + """ + 清理指定区域的缓存 + """ + self.cached_function.cache_clear() + + def get_cache_info(self): + """ + 获取缓存信息 + """ + cache_region = self.cached_function.cache_region + return f"缓存区域: {cache_region}" + ``` + +- 7. 缓存后端自动选择: + - 系统会根据配置自动选择缓存后端: + - `CACHE_BACKEND_TYPE=redis`:使用Redis作为缓存后端 + - `CACHE_BACKEND_TYPE=memory`:使用内存缓存(cachetools) + - 插件代码无需修改,系统会自动处理缓存后端的切换 + +- 8. 最佳实践: + - 为每个插件使用独立的缓存区域(region),避免缓存键冲突 + - 合理设置TTL,避免缓存过期时间过长导致数据过期 + - 对于频繁访问的数据使用较长的TTL,对于实时性要求高的数据使用较短的TTL + - 使用`skip_none=True`避免缓存无意义的None值 + - 大文件或二进制数据建议使用文件缓存后端 + - 在插件卸载时清理相关缓存,避免内存泄漏 + ## 版本发布