{ "cells": [ { "metadata": {}, "cell_type": "markdown", "source": "## 1. 初始化(所有操作前必须运行)", "id": "197b1b81f5528a50" }, { "cell_type": "code", "id": "initial_id", "metadata": { "collapsed": true, "ExecuteTime": { "end_time": "2025-09-18T09:06:59.024834Z", "start_time": "2025-09-18T09:06:58.966690Z" } }, "source": [ "{\n", " \"cells\": [\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"# TaskManager 任务管理类\\n\",\n", " \"任务管理核心组件,负责任务的CRUD、状态切换、手动执行等操作\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"code\",\n", " \"execution_count\": null,\n", " \"metadata\": {},\n", " \"outputs\": [],\n", " \"source\": [\n", " \"import pandas as pd\\n\",\n", " \"from datetime import datetime\\n\",\n", " \"from typing import Dict, List, Optional, Any\\n\",\n", " \"import pytz\\n\",\n", " \"import croniter\\n\",\n", " \"\\n\",\n", " \"from utils.mysql_agent import MySQLAgent\\n\",\n", " \"from utils.logger import CrossPlatformLog\\n\",\n", " \"from system_management.scheduler.task_scheduler import TaskScheduler\\n\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"code\",\n", " \"execution_count\": null,\n", " \"metadata\": {},\n", " \"outputs\": [],\n", " \"source\": [\n", " \"class TaskManager:\\n\",\n", " \" def __init__(self, scheduler: TaskScheduler):\\n\",\n", " \" \\\"\\\"\\\"初始化任务管理器\\n\",\n", " \" Args:\\n\",\n", " \" scheduler: 任务调度器实例\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" self.scheduler = scheduler\\n\",\n", " \" self.db = scheduler.db # 复用调度器的数据库连接\\n\",\n", " \" self.log = CrossPlatformLog.get_logger(\\\"TaskManager\\\")\\n\",\n", " \"\\n\",\n", " \" def get_all_tasks(self, active_only: bool = False) -> List[Dict[str, Any]]:\\n\",\n", " \" \\\"\\\"\\\"获取所有任务列表\\n\",\n", " \" Args:\\n\",\n", " \" active_only: 是否只返回活跃任务\\n\",\n", " \" Returns:\\n\",\n", " \" 任务字典列表\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" try:\\n\",\n", " \" query = \\\"SELECT * FROM main_task\\\"\\n\",\n", " \" params = []\\n\",\n", " \" if active_only:\\n\",\n", " \" query += \\\" WHERE is_active = 1\\\"\\n\",\n", " \" query += \\\" ORDER BY task_id\\\"\\n\",\n", " \"\\n\",\n", " \" tasks_df = self.db.query_to_df(query, params=params)\\n\",\n", " \" return tasks_df.to_dict('records')\\n\",\n", " \" except Exception as e:\\n\",\n", " \" self.log.error(\\\"获取任务列表失败\\\", exc_info=True)\\n\",\n", " \" return []\\n\",\n", " \"\\n\",\n", " \" def get_task_by_id(self, task_id: int) -> Optional[Dict[str, Any]]:\\n\",\n", " \" \\\"\\\"\\\"通过ID获取任务详情\\n\",\n", " \" Args:\\n\",\n", " \" task_id: 任务ID\\n\",\n", " \" Returns:\\n\",\n", " \" 任务字典,不存在则返回None\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" try:\\n\",\n", " \" task_df = self.db.query_to_df(\\n\",\n", " \" \\\"SELECT * FROM main_task WHERE task_id = %s\\\",\\n\",\n", " \" params=(task_id,)\\n\",\n", " \" )\\n\",\n", " \" if task_df.empty:\\n\",\n", " \" return None\\n\",\n", " \" return task_df.iloc[0].to_dict()\\n\",\n", " \" except Exception as e:\\n\",\n", " \" self.log.error(f\\\"获取任务详情失败 (ID: {task_id})\\\")\\n\",\n", " \" return None\\n\",\n", " \"\\n\",\n", " \" def update_task(self, task_id: int, updates: Dict[str, Any]) -> bool:\\n\",\n", " \" \\\"\\\"\\\"更新任务属性\\n\",\n", " \" Args:\\n\",\n", " \" task_id: 任务ID\\n\",\n", " \" updates: 需要更新的字段字典\\n\",\n", " \" Returns:\\n\",\n", " \" 更新是否成功\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" if not updates:\\n\",\n", " \" self.log.warning(\\\"未提供更新字段\\\")\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" try:\\n\",\n", " \" # 处理Cron表达式更新(需重新计算下次运行时间)\\n\",\n", " \" if 'cron_expression' in updates or 'time_zone' in updates:\\n\",\n", " \" task = self.get_task_by_id(task_id)\\n\",\n", " \" if not task:\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" cron_expr = updates.get('cron_expression', task['cron_expression'])\\n\",\n", " \" time_zone = updates.get('time_zone', task['time_zone'])\\n\",\n", " \" updates['next_run_time'] = self.scheduler._calculate_next_run_time(cron_expr, time_zone)\\n\",\n", " \"\\n\",\n", " \" # 执行更新\\n\",\n", " \" self.scheduler._update_task_status(task_id, updates)\\n\",\n", " \" self.log.info(f\\\"任务更新成功 (ID: {task_id})\\\")\\n\",\n", " \" return True\\n\",\n", " \" except Exception as e:\\n\",\n", " \" self.log.error(f\\\"任务更新失败 (ID: {task_id})\\\")\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" def toggle_task_status(self, task_id: int, activate: bool) -> bool:\\n\",\n", " \" \\\"\\\"\\\"切换任务激活状态\\n\",\n", " \" Args:\\n\",\n", " \" task_id: 任务ID\\n\",\n", " \" activate: True=激活, False=禁用\\n\",\n", " \" Returns:\\n\",\n", " \" 操作是否成功\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" try:\\n\",\n", " \" status = 1 if activate else 0\\n\",\n", " \" # 激活时重新计算下次运行时间\\n\",\n", " \" updates = {'is_active': status}\\n\",\n", " \" if activate:\\n\",\n", " \" task = self.get_task_by_id(task_id)\\n\",\n", " \" if task:\\n\",\n", " \" updates['next_run_time'] = self.scheduler._calculate_next_run_time(\\n\",\n", " \" task['cron_expression'], task['time_zone']\\n\",\n", " \" )\\n\",\n", " \"\\n\",\n", " \" self.scheduler._update_task_status(task_id, updates)\\n\",\n", " \" self.log.info(f\\\"任务{'激活' if activate else '禁用'}成功 (ID: {task_id})\\\")\\n\",\n", " \" return True\\n\",\n", " \" except Exception as e:\\n\",\n", " \" self.log.error(f\\\"任务状态切换失败 (ID: {task_id})\\\")\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" def delete_task(self, task_id: int) -> bool:\\n\",\n", " \" \\\"\\\"\\\"删除任务\\n\",\n", " \" Args:\\n\",\n", " \" task_id: 任务ID\\n\",\n", " \" Returns:\\n\",\n", " \" 删除是否成功\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" try:\\n\",\n", " \" # 检查任务是否存在\\n\",\n", " \" if not self.get_task_by_id(task_id):\\n\",\n", " \" self.log.warning(f\\\"任务不存在 (ID: {task_id})\\\")\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" # 执行删除\\n\",\n", " \" self.db.execute_sql(\\n\",\n", " \" \\\"DELETE FROM main_task WHERE task_id = %s\\\",\\n\",\n", " \" params=(task_id,)\\n\",\n", " \" )\\n\",\n", " \" self.log.info(f\\\"任务删除成功 (ID: {task_id})\\\")\\n\",\n", " \" return True\\n\",\n", " \" except Exception as e:\\n\",\n", " \" self.log.error(f\\\"任务删除失败 (ID: {task_id})\\\")\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" def run_task_manually(self, task_id: int) -> bool:\\n\",\n", " \" \\\"\\\"\\\"手动执行任务\\n\",\n", " \" Args:\\n\",\n", " \" task_id: 任务ID\\n\",\n", " \" Returns:\\n\",\n", " \" 执行是否成功\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" try:\\n\",\n", " \" task = self.get_task_by_id(task_id)\\n\",\n", " \" if not task:\\n\",\n", " \" self.log.warning(f\\\"任务不存在 (ID: {task_id})\\\")\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" # 标记任务为运行中\\n\",\n", " \" self.scheduler._update_task_status(task_id, {\\n\",\n", " \" 'is_running': 1,\\n\",\n", " \" 'last_run_time': datetime.now()\\n\",\n", " \" })\\n\",\n", " \"\\n\",\n", " \" # 执行任务逻辑\\n\",\n", " \" self.scheduler._execute_task_logic(task)\\n\",\n", " \"\\n\",\n", " \" # 更新任务状态\\n\",\n", " \" next_run_time = self.scheduler._calculate_next_run_time(\\n\",\n", " \" task['cron_expression'], task['time_zone']\\n\",\n", " \" )\\n\",\n", " \" self.scheduler._update_task_status(task_id, {\\n\",\n", " \" 'is_running': 0,\\n\",\n", " \" 'last_run_status': 'success',\\n\",\n", " \" 'run_count': task['run_count'] + 1,\\n\",\n", " \" 'next_run_time': next_run_time\\n\",\n", " \" })\\n\",\n", " \" return True\\n\",\n", " \" except Exception as e:\\n\",\n", " \" self.scheduler._update_task_status(task_id, {\\n\",\n", " \" 'is_running': 0,\\n\",\n", " \" 'last_run_status': 'failed'\\n\",\n", " \" })\\n\",\n", " \" self.log.error(f\\\"任务手动执行失败 (ID: {task_id})\\\")\\n\",\n", " \" return False\\n\",\n", " \"\\n\",\n", " \" def print_task_table(self, tasks: List[Dict[str, Any]]) -> None:\\n\",\n", " \" \\\"\\\"\\\"格式化打印任务列表\\n\",\n", " \" Args:\\n\",\n", " \" tasks: 任务列表\\n\",\n", " \" \\\"\\\"\\\"\\n\",\n", " \" if not tasks:\\n\",\n", " \" print(\\\"没有任务数据\\\")\\n\",\n", " \" return\\n\",\n", " \"\\n\",\n", " \" # 转换为DataFrame并筛选显示字段\\n\",\n", " \" df = pd.DataFrame(tasks)\\n\",\n", " \" display_cols = [\\n\",\n", " \" 'task_id', 'task_name', 'task_type', 'cron_expression',\\n\",\n", " \" 'is_active', 'last_run_status', 'next_run_time'\\n\",\n", " \" ]\\n\",\n", " \" # 处理状态显示\\n\",\n", " \" df['is_active'] = df['is_active'].map({1: '活跃', 0: '禁用'})\\n\",\n", " \" print(f\\\"共 {len(df)} 个任务\\\\n\\\")\\n\",\n", " \" print(df[display_cols].to_string(index=False))\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"## 使用示例\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"code\",\n", " \"execution_count\": null,\n", " \"metadata\": {},\n", " \"outputs\": [],\n", " \"source\": [\n", " \"# 初始化示例\\n\",\n", " \"from config.config import ConfigManager\\n\",\n", " \"\\n\",\n", " \"# 加载配置\\n\",\n", " \"config = ConfigManager()\\n\",\n", " \"scheduler = TaskScheduler(config.get(\\\"database\\\"))\\n\",\n", " \"manager = TaskManager(scheduler)\\n\",\n", " \"\\n\",\n", " \"# 1. 列出所有任务\\n\",\n", " \"all_tasks = manager.get_all_tasks()\\n\",\n", " \"manager.print_task_table(all_tasks)\\n\",\n", " \"\\n\",\n", " \"# 2. 获取单个任务详情\\n\",\n", " \"task = manager.get_task_by_id(1)\\n\",\n", " \"if task:\\n\",\n", " \" print(\\\"\\\\n任务详情:\\\")\\n\",\n", " \" for k, v in task.items():\\n\",\n", " \" print(f\\\"{k}: {v}\\\")\\n\",\n", " \"\\n\",\n", " \"# 3. 更新任务Cron表达式\\n\",\n", " \"manager.update_task(1, {'cron_expression': '0 */2 * * *'})\\n\",\n", " \"\\n\",\n", " \"# 4. 激活任务\\n\",\n", " \"manager.toggle_task_status(1, activate=True)\\n\",\n", " \"\\n\",\n", " \"# 5. 手动执行任务\\n\",\n", " \"manager.run_task_manually(1)\\n\",\n", " \"\\n\",\n", " \"# 6. 删除任务(谨慎操作)\\n\",\n", " \"# manager.delete_task(1)\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"## 核心功能说明\\n\",\n", " \"- 依赖 `TaskScheduler` 实现底层调度逻辑与数据库交互\\n\",\n", " \"- 支持任务全生命周期管理(查询/更新/激活/执行/删除)\\n\",\n", " \"- 内置日志记录与错误处理\\n\",\n", " \"- 兼容Windows/macOS/Linux多平台\"\n", " ]\n", " }\n", " ],\n", " \"metadata\": {\n", " \"kernelspec\": {\n", " \"display_name\": \"Python 3\",\n", " \"language\": \"python\",\n", " \"name\": \"python3\"\n", " },\n", " \"language_info\": {\n", " \"codemirror_mode\": {\n", " \"name\": \"ipython\",\n", " \"version\": 3\n", " },\n", " \"file_extension\": \".py\",\n", " \"mimetype\": \"text/x-python\",\n", " \"name\": \"python\",\n", " \"nbconvert_exporter\": \"python\",\n", " \"pygments_lexer\": \"ipython3\",\n", " \"version\": \"3.8.10\"\n", " }\n", " },\n", " \"nbformat\": 4,\n", " \"nbformat_minor\": 4\n", "}" ], "outputs": [ { "ename": "NameError", "evalue": "name 'null' is not defined", "output_type": "error", "traceback": [ "\u001B[31m---------------------------------------------------------------------------\u001B[39m", "\u001B[31mNameError\u001B[39m Traceback (most recent call last)", "\u001B[36mCell\u001B[39m\u001B[36m \u001B[39m\u001B[32mIn[4]\u001B[39m\u001B[32m, line 13\u001B[39m\n\u001B[32m 1\u001B[39m {\n\u001B[32m 2\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcells\u001B[39m\u001B[33m\"\u001B[39m: [\n\u001B[32m 3\u001B[39m {\n\u001B[32m 4\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcell_type\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mmarkdown\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 5\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmetadata\u001B[39m\u001B[33m\"\u001B[39m: {},\n\u001B[32m 6\u001B[39m \u001B[33m\"\u001B[39m\u001B[33msource\u001B[39m\u001B[33m\"\u001B[39m: [\n\u001B[32m 7\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# TaskManager 任务管理类\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 8\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m任务管理核心组件,负责任务的CRUD、状态切换、手动执行等操作\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 9\u001B[39m ]\n\u001B[32m 10\u001B[39m },\n\u001B[32m 11\u001B[39m {\n\u001B[32m 12\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcell_type\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mcode\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m---> \u001B[39m\u001B[32m13\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mexecution_count\u001B[39m\u001B[33m\"\u001B[39m: \u001B[43mnull\u001B[49m,\n\u001B[32m 14\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmetadata\u001B[39m\u001B[33m\"\u001B[39m: {},\n\u001B[32m 15\u001B[39m \u001B[33m\"\u001B[39m\u001B[33moutputs\u001B[39m\u001B[33m\"\u001B[39m: [],\n\u001B[32m 16\u001B[39m \u001B[33m\"\u001B[39m\u001B[33msource\u001B[39m\u001B[33m\"\u001B[39m: [\n\u001B[32m 17\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mimport pandas as pd\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 18\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mfrom datetime import datetime\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 19\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mfrom typing import Dict, List, Optional, Any\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 20\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mimport pytz\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 21\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mimport croniter\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 22\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 23\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mfrom utils.mysql_agent import MySQLAgent\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 24\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mfrom utils.logger import CrossPlatformLog\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 25\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mfrom system_management.scheduler.task_scheduler import TaskScheduler\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m\n\u001B[32m 26\u001B[39m ]\n\u001B[32m 27\u001B[39m },\n\u001B[32m 28\u001B[39m {\n\u001B[32m 29\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcell_type\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mcode\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 30\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mexecution_count\u001B[39m\u001B[33m\"\u001B[39m: null,\n\u001B[32m 31\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmetadata\u001B[39m\u001B[33m\"\u001B[39m: {},\n\u001B[32m 32\u001B[39m \u001B[33m\"\u001B[39m\u001B[33moutputs\u001B[39m\u001B[33m\"\u001B[39m: [],\n\u001B[32m 33\u001B[39m \u001B[33m\"\u001B[39m\u001B[33msource\u001B[39m\u001B[33m\"\u001B[39m: [\n\u001B[32m 34\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mclass TaskManager:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 35\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def __init__(self, scheduler: TaskScheduler):\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 36\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m初始化任务管理器\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 37\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 38\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m scheduler: 任务调度器实例\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 39\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 40\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.scheduler = scheduler\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 41\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.db = scheduler.db # 复用调度器的数据库连接\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 42\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log = CrossPlatformLog.get_logger(\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33mTaskManager\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 43\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 44\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def get_all_tasks(self, active_only: bool = False) -> List[Dict[str, Any]]:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 45\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m获取所有任务列表\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 46\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 47\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m active_only: 是否只返回活跃任务\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 48\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Returns:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 49\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m 任务字典列表\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 50\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 51\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m try:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 52\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m query = \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33mSELECT * FROM main_task\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 53\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m params = []\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 54\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if active_only:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 55\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m query += \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m WHERE is_active = 1\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 56\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m query += \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m ORDER BY task_id\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 57\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 58\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m tasks_df = self.db.query_to_df(query, params=params)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 59\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return tasks_df.to_dict(\u001B[39m\u001B[33m'\u001B[39m\u001B[33mrecords\u001B[39m\u001B[33m'\u001B[39m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 60\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m except Exception as e:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 61\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.error(\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m获取任务列表失败\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m, exc_info=True)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 62\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return []\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 63\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 64\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def get_task_by_id(self, task_id: int) -> Optional[Dict[str, Any]]:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 65\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m通过ID获取任务详情\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 66\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 67\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task_id: 任务ID\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 68\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Returns:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 69\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m 任务字典,不存在则返回None\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 70\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 71\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m try:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 72\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task_df = self.db.query_to_df(\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 73\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33mSELECT * FROM main_task WHERE task_id = \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 74\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m params=(task_id,)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 75\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m )\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 76\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if task_df.empty:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 77\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return None\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 78\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return task_df.iloc[0].to_dict()\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 79\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m except Exception as e:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 80\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.error(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m获取任务详情失败 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 81\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return None\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 82\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 83\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def update_task(self, task_id: int, updates: Dict[str, Any]) -> bool:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 84\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m更新任务属性\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 85\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 86\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task_id: 任务ID\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 87\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m updates: 需要更新的字段字典\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 88\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Returns:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 89\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m 更新是否成功\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 90\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 91\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if not updates:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 92\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.warning(\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m未提供更新字段\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 93\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 94\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 95\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m try:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 96\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 处理Cron表达式更新(需重新计算下次运行时间)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 97\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if \u001B[39m\u001B[33m'\u001B[39m\u001B[33mcron_expression\u001B[39m\u001B[33m'\u001B[39m\u001B[33m in updates or \u001B[39m\u001B[33m'\u001B[39m\u001B[33mtime_zone\u001B[39m\u001B[33m'\u001B[39m\u001B[33m in updates:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 98\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task = self.get_task_by_id(task_id)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 99\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if not task:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 100\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 101\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 102\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m cron_expr = updates.get(\u001B[39m\u001B[33m'\u001B[39m\u001B[33mcron_expression\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, task[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mcron_expression\u001B[39m\u001B[33m'\u001B[39m\u001B[33m])\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 103\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m time_zone = updates.get(\u001B[39m\u001B[33m'\u001B[39m\u001B[33mtime_zone\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, task[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mtime_zone\u001B[39m\u001B[33m'\u001B[39m\u001B[33m])\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 104\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m updates[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mnext_run_time\u001B[39m\u001B[33m'\u001B[39m\u001B[33m] = self.scheduler._calculate_next_run_time(cron_expr, time_zone)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 105\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 106\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 执行更新\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 107\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.scheduler._update_task_status(task_id, updates)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 108\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.info(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务更新成功 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 109\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return True\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 110\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m except Exception as e:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 111\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.error(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务更新失败 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 112\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 113\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 114\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def toggle_task_status(self, task_id: int, activate: bool) -> bool:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 115\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m切换任务激活状态\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 116\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 117\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task_id: 任务ID\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 118\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m activate: True=激活, False=禁用\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 119\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Returns:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 120\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m 操作是否成功\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 121\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 122\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m try:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 123\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m status = 1 if activate else 0\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 124\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 激活时重新计算下次运行时间\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 125\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m updates = \u001B[39m\u001B[33m{\u001B[39m\u001B[33m'\u001B[39m\u001B[33mis_active\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: status}\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 126\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if activate:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 127\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task = self.get_task_by_id(task_id)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 128\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if task:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 129\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m updates[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mnext_run_time\u001B[39m\u001B[33m'\u001B[39m\u001B[33m] = self.scheduler._calculate_next_run_time(\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 130\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mcron_expression\u001B[39m\u001B[33m'\u001B[39m\u001B[33m], task[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mtime_zone\u001B[39m\u001B[33m'\u001B[39m\u001B[33m]\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 131\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m )\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 132\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 133\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.scheduler._update_task_status(task_id, updates)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 134\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.info(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务\u001B[39m\u001B[33m{\u001B[39m\u001B[33m'\u001B[39m\u001B[33m激活\u001B[39m\u001B[33m'\u001B[39m\u001B[33m if activate else \u001B[39m\u001B[33m'\u001B[39m\u001B[33m禁用\u001B[39m\u001B[33m'\u001B[39m\u001B[33m}成功 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 135\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return True\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 136\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m except Exception as e:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 137\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.error(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务状态切换失败 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 138\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 139\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 140\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def delete_task(self, task_id: int) -> bool:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 141\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m删除任务\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 142\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 143\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task_id: 任务ID\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 144\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Returns:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 145\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m 删除是否成功\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 146\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 147\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m try:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 148\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 检查任务是否存在\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 149\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if not self.get_task_by_id(task_id):\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 150\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.warning(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务不存在 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 151\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 152\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 153\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 执行删除\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 154\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.db.execute_sql(\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 155\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33mDELETE FROM main_task WHERE task_id = \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 156\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m params=(task_id,)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 157\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m )\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 158\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.info(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务删除成功 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 159\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return True\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 160\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m except Exception as e:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 161\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.error(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务删除失败 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 162\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 163\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 164\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def run_task_manually(self, task_id: int) -> bool:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 165\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m手动执行任务\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 166\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 167\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task_id: 任务ID\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 168\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Returns:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 169\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m 执行是否成功\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 170\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 171\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m try:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 172\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task = self.get_task_by_id(task_id)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 173\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if not task:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 174\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.warning(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务不存在 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 175\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 176\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 177\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 标记任务为运行中\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 178\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.scheduler._update_task_status(task_id, \u001B[39m\u001B[33m{\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 179\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mis_running\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: 1,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 180\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mlast_run_time\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: datetime.now()\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 181\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m })\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 182\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 183\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 执行任务逻辑\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 184\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.scheduler._execute_task_logic(task)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 185\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 186\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 更新任务状态\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 187\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m next_run_time = self.scheduler._calculate_next_run_time(\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 188\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m task[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mcron_expression\u001B[39m\u001B[33m'\u001B[39m\u001B[33m], task[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mtime_zone\u001B[39m\u001B[33m'\u001B[39m\u001B[33m]\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 189\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m )\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 190\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.scheduler._update_task_status(task_id, \u001B[39m\u001B[33m{\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 191\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mis_running\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: 0,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 192\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mlast_run_status\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: \u001B[39m\u001B[33m'\u001B[39m\u001B[33msuccess\u001B[39m\u001B[33m'\u001B[39m\u001B[33m,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 193\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mrun_count\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: task[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mrun_count\u001B[39m\u001B[33m'\u001B[39m\u001B[33m] + 1,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 194\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mnext_run_time\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: next_run_time\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 195\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m })\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 196\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return True\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 197\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m except Exception as e:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 198\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.scheduler._update_task_status(task_id, \u001B[39m\u001B[33m{\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 199\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mis_running\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: 0,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 200\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mlast_run_status\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: \u001B[39m\u001B[33m'\u001B[39m\u001B[33mfailed\u001B[39m\u001B[33m'\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 201\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m })\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 202\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m self.log.error(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m任务手动执行失败 (ID: \u001B[39m\u001B[38;5;132;01m{task_id}\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 203\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return False\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 204\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 205\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m def print_task_table(self, tasks: List[Dict[str, Any]]) -> None:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 206\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m格式化打印任务列表\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 207\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m Args:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 208\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m tasks: 任务列表\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 209\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 210\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m if not tasks:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 211\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m print(\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m没有任务数据\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 212\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m return\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 213\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 214\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 转换为DataFrame并筛选显示字段\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 215\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m df = pd.DataFrame(tasks)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 216\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m display_cols = [\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 217\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mtask_id\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, \u001B[39m\u001B[33m'\u001B[39m\u001B[33mtask_name\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, \u001B[39m\u001B[33m'\u001B[39m\u001B[33mtask_type\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, \u001B[39m\u001B[33m'\u001B[39m\u001B[33mcron_expression\u001B[39m\u001B[33m'\u001B[39m\u001B[33m,\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 218\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m \u001B[39m\u001B[33m'\u001B[39m\u001B[33mis_active\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, \u001B[39m\u001B[33m'\u001B[39m\u001B[33mlast_run_status\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, \u001B[39m\u001B[33m'\u001B[39m\u001B[33mnext_run_time\u001B[39m\u001B[33m'\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 219\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m ]\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 220\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m # 处理状态显示\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 221\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m df[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mis_active\u001B[39m\u001B[33m'\u001B[39m\u001B[33m] = df[\u001B[39m\u001B[33m'\u001B[39m\u001B[33mis_active\u001B[39m\u001B[33m'\u001B[39m\u001B[33m].map(\u001B[39m\u001B[33m{\u001B[39m\u001B[33m1: \u001B[39m\u001B[33m'\u001B[39m\u001B[33m活跃\u001B[39m\u001B[33m'\u001B[39m\u001B[33m, 0: \u001B[39m\u001B[33m'\u001B[39m\u001B[33m禁用\u001B[39m\u001B[33m'\u001B[39m\u001B[33m})\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 222\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m print(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m共 \u001B[39m\u001B[33m{\u001B[39m\u001B[33mlen(df)} 个任务\u001B[39m\u001B[38;5;130;01m\\\\\u001B[39;00m\u001B[33mn\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 223\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m print(df[display_cols].to_string(index=False))\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 224\u001B[39m ]\n\u001B[32m 225\u001B[39m },\n\u001B[32m 226\u001B[39m {\n\u001B[32m 227\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcell_type\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mmarkdown\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 228\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmetadata\u001B[39m\u001B[33m\"\u001B[39m: {},\n\u001B[32m 229\u001B[39m \u001B[33m\"\u001B[39m\u001B[33msource\u001B[39m\u001B[33m\"\u001B[39m: [\n\u001B[32m 230\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m## 使用示例\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 231\u001B[39m ]\n\u001B[32m 232\u001B[39m },\n\u001B[32m 233\u001B[39m {\n\u001B[32m 234\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcell_type\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mcode\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 235\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mexecution_count\u001B[39m\u001B[33m\"\u001B[39m: null,\n\u001B[32m 236\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmetadata\u001B[39m\u001B[33m\"\u001B[39m: {},\n\u001B[32m 237\u001B[39m \u001B[33m\"\u001B[39m\u001B[33moutputs\u001B[39m\u001B[33m\"\u001B[39m: [],\n\u001B[32m 238\u001B[39m \u001B[33m\"\u001B[39m\u001B[33msource\u001B[39m\u001B[33m\"\u001B[39m: [\n\u001B[32m 239\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 初始化示例\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 240\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mfrom config.config import ConfigManager\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 241\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 242\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 加载配置\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 243\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mconfig = ConfigManager()\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 244\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mscheduler = TaskScheduler(config.get(\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33mdatabase\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m))\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 245\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmanager = TaskManager(scheduler)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 246\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 247\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 1. 列出所有任务\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 248\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mall_tasks = manager.get_all_tasks()\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 249\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmanager.print_task_table(all_tasks)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 250\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 251\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 2. 获取单个任务详情\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 252\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mtask = manager.get_task_by_id(1)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 253\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mif task:\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 254\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m print(\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;130;01m\\\\\u001B[39;00m\u001B[33mn任务详情:\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 255\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m for k, v in task.items():\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 256\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m print(f\u001B[39m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[38;5;132;01m{k}\u001B[39;00m\u001B[33m: \u001B[39m\u001B[38;5;132;01m{v}\u001B[39;00m\u001B[38;5;130;01m\\\"\u001B[39;00m\u001B[33m)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 257\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 258\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 3. 更新任务Cron表达式\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 259\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmanager.update_task(1, \u001B[39m\u001B[33m{\u001B[39m\u001B[33m'\u001B[39m\u001B[33mcron_expression\u001B[39m\u001B[33m'\u001B[39m\u001B[33m: \u001B[39m\u001B[33m'\u001B[39m\u001B[33m0 */2 * * *\u001B[39m\u001B[33m'\u001B[39m\u001B[33m})\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 260\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 261\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 4. 激活任务\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 262\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmanager.toggle_task_status(1, activate=True)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 263\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 264\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 5. 手动执行任务\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 265\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmanager.run_task_manually(1)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 266\u001B[39m \u001B[33m\"\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 267\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# 6. 删除任务(谨慎操作)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 268\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m# manager.delete_task(1)\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 269\u001B[39m ]\n\u001B[32m 270\u001B[39m },\n\u001B[32m 271\u001B[39m {\n\u001B[32m 272\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcell_type\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mmarkdown\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 273\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmetadata\u001B[39m\u001B[33m\"\u001B[39m: {},\n\u001B[32m 274\u001B[39m \u001B[33m\"\u001B[39m\u001B[33msource\u001B[39m\u001B[33m\"\u001B[39m: [\n\u001B[32m 275\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m## 核心功能说明\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 276\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m- 依赖 `TaskScheduler` 实现底层调度逻辑与数据库交互\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 277\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m- 支持任务全生命周期管理(查询/更新/激活/执行/删除)\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 278\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m- 内置日志记录与错误处理\u001B[39m\u001B[38;5;130;01m\\n\u001B[39;00m\u001B[33m\"\u001B[39m,\n\u001B[32m 279\u001B[39m \u001B[33m\"\u001B[39m\u001B[33m- 兼容Windows/macOS/Linux多平台\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 280\u001B[39m ]\n\u001B[32m 281\u001B[39m }\n\u001B[32m 282\u001B[39m ],\n\u001B[32m 283\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmetadata\u001B[39m\u001B[33m\"\u001B[39m: {\n\u001B[32m 284\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mkernelspec\u001B[39m\u001B[33m\"\u001B[39m: {\n\u001B[32m 285\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mdisplay_name\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mPython 3\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 286\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mlanguage\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mpython\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 287\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mname\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mpython3\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 288\u001B[39m },\n\u001B[32m 289\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mlanguage_info\u001B[39m\u001B[33m\"\u001B[39m: {\n\u001B[32m 290\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mcodemirror_mode\u001B[39m\u001B[33m\"\u001B[39m: {\n\u001B[32m 291\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mname\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mipython\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 292\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mversion\u001B[39m\u001B[33m\"\u001B[39m: \u001B[32m3\u001B[39m\n\u001B[32m 293\u001B[39m },\n\u001B[32m 294\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mfile_extension\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33m.py\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 295\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mmimetype\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mtext/x-python\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 296\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mname\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mpython\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 297\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mnbconvert_exporter\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mpython\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 298\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mpygments_lexer\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33mipython3\u001B[39m\u001B[33m\"\u001B[39m,\n\u001B[32m 299\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mversion\u001B[39m\u001B[33m\"\u001B[39m: \u001B[33m\"\u001B[39m\u001B[33m3.8.10\u001B[39m\u001B[33m\"\u001B[39m\n\u001B[32m 300\u001B[39m }\n\u001B[32m 301\u001B[39m },\n\u001B[32m 302\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mnbformat\u001B[39m\u001B[33m\"\u001B[39m: \u001B[32m4\u001B[39m,\n\u001B[32m 303\u001B[39m \u001B[33m\"\u001B[39m\u001B[33mnbformat_minor\u001B[39m\u001B[33m\"\u001B[39m: \u001B[32m4\u001B[39m\n\u001B[32m 304\u001B[39m }\n", "\u001B[31mNameError\u001B[39m: name 'null' is not defined" ] } ], "execution_count": 4 }, { "metadata": {}, "cell_type": "markdown", "source": "## 2. 列出任务(对应命令行 list)", "id": "8271189cef3b5f17" }, { "metadata": { "ExecuteTime": { "end_time": "2025-09-18T09:06:51.924812Z", "start_time": "2025-09-18T09:06:51.885005Z" } }, "cell_type": "code", "source": [ "# 列出所有任务(包括已禁用的)\n", "def list_tasks(active_only=True):\n", " tasks = manager.get_all_tasks(active_only)\n", " if not tasks:\n", " display(Markdown(\"### 没有找到任务\"))\n", " return None\n", "\n", " df = pd.DataFrame(tasks)\n", "\n", " # 格式化日期列\n", " if 'last_run_time' in df.columns:\n", " df['last_run_time'] = df['last_run_time'].apply(format_datetime)\n", " if 'next_run_time' in df.columns:\n", " df['next_run_time'] = df['next_run_time'].apply(format_datetime)\n", "\n", " # 重命名列名\n", " df = df.rename(columns={\n", " 'task_id': '任务ID',\n", " 'task_name': '任务名称',\n", " 'task_type': '任务类型',\n", " 'module_path': '模块路径',\n", " 'cron_expression': 'Cron表达式',\n", " 'time_zone': '时区',\n", " 'last_run_time': '最后运行时间',\n", " 'next_run_time': '下次运行时间',\n", " 'last_run_status': '运行状态',\n", " 'is_active': '是否活跃',\n", " 'run_count': '运行次数'\n", " })\n", "\n", " display(Markdown(\"### 任务列表\"))\n", " display(HTML(df.to_html(index=False)))\n", " return df\n", "\n", "# 执行:列出所有任务(包括已禁用)\n", "list_tasks(active_only=False)\n", "\n", "# 或者:只列出活跃任务\n", "# list_tasks(active_only=True)" ], "id": "7b020af55972643", "outputs": [ { "ename": "NameError", "evalue": "name 'manager' is not defined", "output_type": "error", "traceback": [ "\u001B[31m---------------------------------------------------------------------------\u001B[39m", "\u001B[31mNameError\u001B[39m Traceback (most recent call last)", "\u001B[36mCell\u001B[39m\u001B[36m \u001B[39m\u001B[32mIn[3]\u001B[39m\u001B[32m, line 36\u001B[39m\n\u001B[32m 33\u001B[39m \u001B[38;5;28;01mreturn\u001B[39;00m df\n\u001B[32m 35\u001B[39m \u001B[38;5;66;03m# 执行:列出所有任务(包括已禁用)\u001B[39;00m\n\u001B[32m---> \u001B[39m\u001B[32m36\u001B[39m \u001B[43mlist_tasks\u001B[49m\u001B[43m(\u001B[49m\u001B[43mactive_only\u001B[49m\u001B[43m=\u001B[49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m)\u001B[49m\n\u001B[32m 38\u001B[39m \u001B[38;5;66;03m# 或者:只列出活跃任务\u001B[39;00m\n\u001B[32m 39\u001B[39m \u001B[38;5;66;03m# list_tasks(active_only=True)\u001B[39;00m\n", "\u001B[36mCell\u001B[39m\u001B[36m \u001B[39m\u001B[32mIn[3]\u001B[39m\u001B[32m, line 3\u001B[39m, in \u001B[36mlist_tasks\u001B[39m\u001B[34m(active_only)\u001B[39m\n\u001B[32m 2\u001B[39m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[34mlist_tasks\u001B[39m(active_only=\u001B[38;5;28;01mTrue\u001B[39;00m):\n\u001B[32m----> \u001B[39m\u001B[32m3\u001B[39m tasks = \u001B[43mmanager\u001B[49m.get_all_tasks(active_only)\n\u001B[32m 4\u001B[39m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m tasks:\n\u001B[32m 5\u001B[39m display(Markdown(\u001B[33m\"\u001B[39m\u001B[33m### 没有找到任务\u001B[39m\u001B[33m\"\u001B[39m))\n", "\u001B[31mNameError\u001B[39m: name 'manager' is not defined" ] } ], "execution_count": 3 }, { "metadata": {}, "cell_type": "markdown", "source": "## 3. 查看任务详情(对应命令行 show)", "id": "7780dcef67a0534c" }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, "source": [ "# 查看指定任务的详情\n", "def show_task_details(task_id):\n", " task = manager.get_task_by_id(task_id)\n", " if not task:\n", " display(Markdown(f\"### 未找到任务ID为 {task_id} 的任务\"))\n", " return None\n", "\n", " details = [\"### 任务详情\"]\n", " details.append(f\"**任务ID**: {task.get('task_id')}\")\n", " details.append(f\"**任务名称**: {task.get('task_name')}\")\n", " details.append(f\"**任务类型**: {task.get('task_type')}\")\n", " details.append(f\"**模块路径**: {task.get('module_path')}\")\n", " details.append(f\"**Cron表达式**: {task.get('cron_expression')}\")\n", " details.append(f\"**时区**: {task.get('time_zone', 'Asia/Shanghai')}\")\n", " details.append(f\"**最后运行时间**: {format_datetime(task.get('last_run_time'))}\")\n", " details.append(f\"**下次运行时间**: {format_datetime(task.get('next_run_time'))}\")\n", " details.append(f\"**运行状态**: {task.get('last_run_status', '未运行')}\")\n", " details.append(f\"**是否活跃**: {'是' if task.get('is_active') else '否'}\")\n", " details.append(f\"**运行次数**: {task.get('run_count', 0)}\")\n", " details.append(f\"**创建时间**: {format_datetime(task.get('created_at'))}\")\n", "\n", " display(Markdown('\\n'.join(details)))\n", " return task\n", "\n", "# 执行:查看任务ID为1的详情(替换为实际ID)\n", "show_task_details(1)" ], "id": "eab90de72c35429e" }, { "metadata": {}, "cell_type": "markdown", "source": "## 4. 添加新任务(对应命令行 add)", "id": "a313f1524f5a54bc" }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, "source": [ "# 添加新任务\n", "def add_new_task(name, task_type, module_path, cron_expression, timezone=\"Asia/Shanghai\"):\n", " try:\n", " task_id = scheduler.add_task(\n", " task_name=name,\n", " task_type=task_type,\n", " module_path=module_path,\n", " cron_expression=cron_expression,\n", " time_zone=timezone\n", " )\n", " display(Markdown(f\"### 任务添加成功!\"))\n", " display(Markdown(f\"新任务ID: {task_id},任务名称: {name}\"))\n", " return task_id\n", " except Exception as e:\n", " display(Markdown(f\"### 添加任务失败: {str(e)}\"))\n", " return None\n", "\n", "# 执行:添加一个新闻采集任务\n", "add_new_task(\n", " name=\"每日新闻采集\",\n", " task_type=\"collector\",\n", " module_path=\"collectors.news_collector\",\n", " cron_expression=\"0 9 * * *\", # 每天9点执行\n", " timezone=\"Asia/Shanghai\"\n", ")" ], "id": "2b2d723bb8e2784f" }, { "metadata": {}, "cell_type": "markdown", "source": "## 5. 更新任务属性(对应命令行 update)", "id": "12373bcbb4a0b434" }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, "source": [ "# 更新任务属性\n", "def update_task(task_id, **kwargs):\n", " updates = {}\n", " if 'name' in kwargs and kwargs['name']:\n", " updates['task_name'] = kwargs['name']\n", " if 'type' in kwargs and kwargs['type']:\n", " updates['task_type'] = kwargs['type']\n", " if 'module' in kwargs and kwargs['module']:\n", " updates['module_path'] = kwargs['module']\n", " if 'cron' in kwargs and kwargs['cron']:\n", " updates['cron_expression'] = kwargs['cron']\n", " if 'timezone' in kwargs and kwargs['timezone']:\n", " updates['time_zone'] = kwargs['timezone']\n", "\n", " if not updates:\n", " display(Markdown(\"### 没有提供任何更新内容\"))\n", " return False\n", "\n", " success = manager.update_task(task_id, updates)\n", " if success:\n", " display(Markdown(f\"### 任务ID {task_id} 更新成功\"))\n", " show_task_details(task_id) # 显示更新后的详情\n", " else:\n", " display(Markdown(f\"### 任务ID {task_id} 更新失败\"))\n", " return success\n", "\n", "# 执行:更新任务(示例:修改任务1的Cron表达式为每天10点)\n", "update_task(1, cron=\"0 10 * * *\")\n", "\n", "# 执行:同时更新多个属性(名称和Cron表达式)\n", "# update_task(1, name=\"每日早间新闻采集\", cron=\"0 8 * * *\")" ], "id": "c892fd8ad2f0dd9d" }, { "metadata": {}, "cell_type": "markdown", "source": "## 6. 启用 / 禁用任务(对应命令行 toggle)", "id": "37564011cf5aa501" }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, "source": [ "# 启用或禁用任务\n", "def toggle_task_status(task_id, activate=True):\n", " success = manager.toggle_task_status(task_id, activate)\n", " action = \"启用\" if activate else \"禁用\"\n", " if success:\n", " display(Markdown(f\"### 任务ID {task_id} {action}成功\"))\n", " else:\n", " display(Markdown(f\"### 任务ID {task_id} {action}失败\"))\n", " return success\n", "\n", "# 执行:启用任务ID为1的任务\n", "toggle_task_status(1, activate=True)\n", "\n", "# 执行:禁用任务ID为1的任务\n", "# toggle_task_status(1, activate=False)" ], "id": "65388d10c5c8d407" }, { "metadata": {}, "cell_type": "markdown", "source": "## 7. 手动执行任务(对应命令行 run)", "id": "c554c748169d5ac8" }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, "source": [ "# 手动执行任务\n", "def run_task_manually(task_id):\n", " display(Markdown(f\"### 正在手动执行任务ID {task_id}...\"))\n", " success = manager.run_task_manually(task_id)\n", " if success:\n", " display(Markdown(f\"### 任务ID {task_id} 执行成功\"))\n", " else:\n", " display(Markdown(f\"### 任务ID {task_id} 执行失败\"))\n", " return success\n", "\n", "# 执行:手动运行任务ID为1的任务\n", "run_task_manually(1)" ], "id": "94892f4134316f8e" }, { "metadata": {}, "cell_type": "markdown", "source": "## 8. 删除任务(对应命令行 delete)", "id": "c3492a1af7dbf2b1" }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, "source": [ "# 删除任务\n", "def delete_task(task_id, confirm=False):\n", " if not confirm:\n", " display(Markdown(f\"### 警告:删除任务是不可逆操作!\"))\n", " display(Markdown(f\"请运行 `delete_task({task_id}, confirm=True)` 确认删除\"))\n", " return False\n", "\n", " success = manager.delete_task(task_id)\n", " if success:\n", " display(Markdown(f\"### 任务ID {task_id} 删除成功\"))\n", " else:\n", " display(Markdown(f\"### 任务ID {task_id} 删除失败\"))\n", " return success\n", "\n", "# 执行:第一步 - 确认删除(不会实际删除)\n", "delete_task(1)\n", "\n", "# 执行:第二步 - 实际删除(谨慎操作!)\n", "# delete_task(1, confirm=True)" ], "id": "6936dcc673933a8d" } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 5 }