系统业务任务插件化迁移:下沉7项非刚需任务并接入平滑迁移
- 系统任务保留刚需三项:登录巡检、消息计数入库、媒体补偿处理;移除新闻/Epic/排行/PDF/秀人维护等业务型系统任务定义\n- 新增 daily_news、epic_free、daily_ranking、sehuatang_push 四个插件,将原系统业务任务改为插件可调度动作\n- 扩展 xiuren_image 插件调度动作,新增秀人下载、绅士R15下载、图片缓存更新三项维护任务\n- 新增系统任务到插件任务的幂等迁移逻辑:按旧 job_key 映射到插件 action,同步 trigger_type/trigger_config/enabled,并通过 payload 标记防止反复覆盖\n- 在 Robot 启动流程中接入迁移执行与重载,并清理已迁移的历史系统任务记录,避免后台双份维护\n- 扩展插件调度数据库操作:支持按 plugin_name + action_key 精确查询,便于迁移与对账
This commit is contained in:
@@ -23,6 +23,60 @@ class PluginScheduleManager:
|
||||
self.db.init_tables()
|
||||
self.reload_from_db()
|
||||
|
||||
def migrate_from_system_jobs(self, system_job_db) -> Dict[str, int]:
|
||||
"""把历史系统任务配置迁移到插件任务表(幂等)。"""
|
||||
# 迁移映射:旧 system_job_key -> (插件显示名, 插件动作 key)
|
||||
migration_map = {
|
||||
"news_baidu_report_auto": ("每日新闻", "baidu_news_daily_push"),
|
||||
"epic_free_games": ("Epic播报", "weekly_free_games_push"),
|
||||
"message_ranking_push": ("每日排行", "daily_message_ranking_push"),
|
||||
"sehuatang_pdf_push": ("涩图推送", "daily_pdf_push"),
|
||||
"xiuren_download": ("秀人图片", "resource_xiuren_download"),
|
||||
"shenshi_r15_download": ("秀人图片", "resource_shenshi_r15_download"),
|
||||
"update_image_cache": ("秀人图片", "resource_update_image_cache"),
|
||||
}
|
||||
|
||||
migrated = 0
|
||||
skipped = 0
|
||||
failed = 0
|
||||
for job_key, target in migration_map.items():
|
||||
plugin_name, action_key = target
|
||||
try:
|
||||
sys_row = system_job_db.get_job(job_key)
|
||||
if not sys_row:
|
||||
skipped += 1
|
||||
continue
|
||||
schedule_row = self.db.get_schedule_by_plugin_action(plugin_name, action_key)
|
||||
if not schedule_row:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
# 通过 payload 标记是否已经迁移,避免每次启动覆盖用户后续修改。
|
||||
payload = schedule_row.get("payload") or {}
|
||||
if payload.get("_migrated_from_system_job") == job_key:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
payload["_migrated_from_system_job"] = job_key
|
||||
updates = {
|
||||
"trigger_type": sys_row.get("trigger_type", schedule_row.get("trigger_type")),
|
||||
"trigger_config": sys_row.get("trigger_config") or schedule_row.get("trigger_config") or {},
|
||||
"enabled": bool(sys_row.get("enabled", 1)),
|
||||
"payload": payload,
|
||||
}
|
||||
# 名称/描述尽量沿用用户在插件端的展示,但允许继承旧系统任务描述。
|
||||
if sys_row.get("description"):
|
||||
updates["description"] = sys_row.get("description")
|
||||
if self.db.update_schedule(int(schedule_row["id"]), updates):
|
||||
migrated += 1
|
||||
else:
|
||||
failed += 1
|
||||
except Exception as e:
|
||||
failed += 1
|
||||
logger.error(f"系统任务迁移到插件任务失败: job_key={job_key}, error={e}")
|
||||
|
||||
return {"migrated": migrated, "skipped": skipped, "failed": failed}
|
||||
|
||||
def _get_plugin_actions(self) -> List[Dict[str, Any]]:
|
||||
actions = []
|
||||
for plugin in self.plugin_manager.plugins.values():
|
||||
|
||||
@@ -3,8 +3,6 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Awaitable, Callable, Dict, List
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from db.system_job_db import SystemJobDBOperator
|
||||
from utils.decorator.async_job import async_job
|
||||
|
||||
@@ -16,22 +14,6 @@ def get_system_job_definitions(robot) -> List[Dict[str, Any]]:
|
||||
调度时间、启停状态全部从数据库 t_system_jobs 读取。
|
||||
"""
|
||||
return [
|
||||
{
|
||||
"job_key": "news_baidu_report_auto",
|
||||
"name": "百度新闻日报",
|
||||
"description": "每天 08:30 推送百度新闻",
|
||||
"trigger_type": "at_times",
|
||||
"trigger_config": {"time_list": ["08:30"]},
|
||||
"handler": robot.news_baidu_report_auto,
|
||||
},
|
||||
{
|
||||
"job_key": "epic_free_games",
|
||||
"name": "Epic 免费游戏推送",
|
||||
"description": "每周五 10:00 推送 Epic 免费游戏",
|
||||
"trigger_type": "every_weekday_time",
|
||||
"trigger_config": {"weekday": 4, "time_str": "10:00"},
|
||||
"handler": robot.send_epic_free_games,
|
||||
},
|
||||
{
|
||||
"job_key": "message_count_to_db",
|
||||
"name": "消息计数入库",
|
||||
@@ -40,38 +22,6 @@ def get_system_job_definitions(robot) -> List[Dict[str, Any]]:
|
||||
"trigger_config": {"time_list": ["02:30"]},
|
||||
"handler": robot.message_count_to_db,
|
||||
},
|
||||
{
|
||||
"job_key": "message_ranking_push",
|
||||
"name": "群消息排行推送",
|
||||
"description": "每天 09:30 生成并发送群消息排行",
|
||||
"trigger_type": "at_times",
|
||||
"trigger_config": {"time_list": ["09:30"]},
|
||||
"handler": robot.generate_and_send_ranking,
|
||||
},
|
||||
{
|
||||
"job_key": "sehuatang_pdf_push",
|
||||
"name": "涩图 PDF 推送",
|
||||
"description": "每天 15:30 生成并发送涩图 PDF",
|
||||
"trigger_type": "at_times",
|
||||
"trigger_config": {"time_list": ["15:30"]},
|
||||
"handler": robot.generate_sehuatang_pdf,
|
||||
},
|
||||
{
|
||||
"job_key": "xiuren_download",
|
||||
"name": "秀人网下载任务",
|
||||
"description": "每天 01:30 执行秀人网下载任务",
|
||||
"trigger_type": "at_times",
|
||||
"trigger_config": {"time_list": ["01:30"]},
|
||||
"handler": robot.xiu_ren_download_task,
|
||||
},
|
||||
{
|
||||
"job_key": "shenshi_r15_download",
|
||||
"name": "绅士 R15 下载任务",
|
||||
"description": "每天 02:30 执行绅士 R15 下载任务",
|
||||
"trigger_type": "at_times",
|
||||
"trigger_config": {"time_list": ["02:30"]},
|
||||
"handler": robot.shen_shi_download_task,
|
||||
},
|
||||
{
|
||||
"job_key": "login_check",
|
||||
"name": "登录状态巡检",
|
||||
@@ -80,14 +30,6 @@ def get_system_job_definitions(robot) -> List[Dict[str, Any]]:
|
||||
"trigger_config": {"time_list": ["14:43"]},
|
||||
"handler": robot.login_twice_auto_auth,
|
||||
},
|
||||
{
|
||||
"job_key": "update_image_cache",
|
||||
"name": "图片缓存更新",
|
||||
"description": "每天 05:00 扫描并更新图片缓存",
|
||||
"trigger_type": "at_times",
|
||||
"trigger_config": {"time_list": ["05:00"]},
|
||||
"handler": _build_image_cache_handler(robot),
|
||||
},
|
||||
{
|
||||
"job_key": "process_pending_images",
|
||||
"name": "待下载图片补偿处理",
|
||||
@@ -98,19 +40,6 @@ def get_system_job_definitions(robot) -> List[Dict[str, Any]]:
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _build_image_cache_handler(robot) -> Callable[[], Awaitable[None]]:
|
||||
async def _handler():
|
||||
from plugins.xiuren_image.images_cache import ImageCacheManager
|
||||
|
||||
logger.info("开始执行图片缓存更新任务")
|
||||
manager = ImageCacheManager("/mnt/nfs_share")
|
||||
await manager.update_image_cache()
|
||||
logger.info("图片缓存更新完成")
|
||||
|
||||
return _handler
|
||||
|
||||
|
||||
def _build_process_pending_images_handler(robot) -> Callable[[], Awaitable[None]]:
|
||||
async def _handler():
|
||||
if hasattr(robot, "message_storage") and robot.message_storage:
|
||||
|
||||
Reference in New Issue
Block a user