Files
intelligence_system/tools/task_manager.ipynb
T
2025-09-19 13:57:55 +08:00

653 lines
80 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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
}