feat: 新增后台任务系统,支持抓取任务在后台持续运行
- 新增后台任务API (/api/tasks) - 抓取任务在后台独立运行,不受页面刷新影响 - 支持任务状态查询和手动停止 - 新增后台任务管理界面 - 数据库新增 background_tasks 表 - 前端使用轮询方式更新任务进度
This commit is contained in:
+178
@@ -0,0 +1,178 @@
|
||||
"""
|
||||
后台任务 API 路由
|
||||
"""
|
||||
from flask import Blueprint, jsonify, request
|
||||
from services.task_service import task_service
|
||||
from models.database import db
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger('tasks_api')
|
||||
|
||||
bp = Blueprint('tasks', __name__, url_prefix='/api/tasks')
|
||||
|
||||
|
||||
@bp.route('/start', methods=['POST'])
|
||||
def start_task():
|
||||
"""
|
||||
启动后台抓取任务
|
||||
|
||||
请求体:
|
||||
{
|
||||
"results": [{"title": "...", "url": "..."}, ...],
|
||||
"auto_save": true,
|
||||
"category": "AI模型",
|
||||
"keywords": ["关键词1", "关键词2"]
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data or 'results' not in data:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '缺少 results 参数'
|
||||
}), 400
|
||||
|
||||
results = data.get('results', [])
|
||||
auto_save = data.get('auto_save', False)
|
||||
category = data.get('category', '')
|
||||
keywords = data.get('keywords', [])
|
||||
|
||||
if not results:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '结果列表为空'
|
||||
}), 400
|
||||
|
||||
# 启动后台任务
|
||||
task_id = task_service.start_fetch_task(
|
||||
results=results,
|
||||
auto_save=auto_save,
|
||||
category=category,
|
||||
keywords=keywords
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'task_id': task_id,
|
||||
'message': f'任务已启动,共 {len(results)} 个URL'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"启动任务失败: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}), 500
|
||||
|
||||
|
||||
@bp.route('/<task_id>/status', methods=['GET'])
|
||||
def get_task_status(task_id):
|
||||
"""获取任务状态"""
|
||||
task = task_service.get_task_status(task_id)
|
||||
|
||||
if not task:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '任务不存在'
|
||||
}), 404
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'task': task
|
||||
})
|
||||
|
||||
|
||||
@bp.route('/<task_id>/stop', methods=['POST'])
|
||||
def stop_task(task_id):
|
||||
"""停止任务"""
|
||||
task = db.get_task(task_id)
|
||||
|
||||
if not task:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '任务不存在'
|
||||
}), 404
|
||||
|
||||
if task['status'] not in ('pending', 'running'):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '任务已完成或已停止'
|
||||
}), 400
|
||||
|
||||
# 设置停止标志
|
||||
if task_service.stop_task(task_id):
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '已请求停止任务'
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '停止任务失败'
|
||||
}), 500
|
||||
|
||||
|
||||
@bp.route('/active', methods=['GET'])
|
||||
def get_active_tasks():
|
||||
"""获取活动任务列表"""
|
||||
tasks = task_service.get_active_tasks()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'tasks': tasks,
|
||||
'count': len(tasks)
|
||||
})
|
||||
|
||||
|
||||
@bp.route('/recent', methods=['GET'])
|
||||
def get_recent_tasks():
|
||||
"""获取最近的任务"""
|
||||
limit = request.args.get('limit', 20, type=int)
|
||||
tasks = db.get_recent_tasks(limit)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'tasks': tasks,
|
||||
'count': len(tasks)
|
||||
})
|
||||
|
||||
|
||||
@bp.route('/<task_id>', methods=['DELETE'])
|
||||
def delete_task(task_id):
|
||||
"""删除任务记录"""
|
||||
task = db.get_task(task_id)
|
||||
|
||||
if not task:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '任务不存在'
|
||||
}), 404
|
||||
|
||||
if task['status'] in ('pending', 'running'):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '任务仍在运行,请先停止'
|
||||
}), 400
|
||||
|
||||
if db.delete_task(task_id):
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '任务已删除'
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': '删除失败'
|
||||
}), 500
|
||||
|
||||
|
||||
@bp.route('/clear', methods=['POST'])
|
||||
def clear_completed_tasks():
|
||||
"""清理已完成的任务"""
|
||||
count = db.clear_completed_tasks()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'已清理 {count} 个任务'
|
||||
})
|
||||
Reference in New Issue
Block a user