653 lines
80 KiB
Plaintext
653 lines
80 KiB
Plaintext
{
|
||
"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
|
||
}
|