[3.1-3.5] FAM-Edge 全链路 - API-Gateway/Video-Preprocessor/AI-Orchestrator/模型适配器(基类+Ollama+Gemini)/熔断器/JSON解析容错 + 配置
This commit is contained in:
0
fam-edge/src/fam_edge/api_gateway/__init__.py
Normal file
0
fam-edge/src/fam_edge/api_gateway/__init__.py
Normal file
89
fam-edge/src/fam_edge/api_gateway/api_gateway.py
Normal file
89
fam-edge/src/fam_edge/api_gateway/api_gateway.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
API-Gateway - Flask 蓝图,接收任务
|
||||
|
||||
同时只允许 1 个任务在处理;新任务到达时若当前有任务处理中,返回 429
|
||||
"""
|
||||
import threading
|
||||
from flask import Blueprint, request, jsonify
|
||||
|
||||
from ..logger import setup_logger
|
||||
from ..ai_orchestrator.orchestrator import AIOrchestrator
|
||||
|
||||
logger = setup_logger('fam-edge.api_gateway')
|
||||
|
||||
api_bp = Blueprint('api_gateway', __name__)
|
||||
|
||||
# 并发控制:同时只允许 1 个任务
|
||||
_current_task_lock = threading.Lock()
|
||||
_currently_processing = False
|
||||
|
||||
_orchestrator = None
|
||||
|
||||
|
||||
def get_orchestrator():
|
||||
global _orchestrator
|
||||
if _orchestrator is None:
|
||||
_orchestrator = AIOrchestrator()
|
||||
return _orchestrator
|
||||
|
||||
|
||||
@api_bp.route('/api/edge/video/analyze', methods=['POST'])
|
||||
def receive_task():
|
||||
"""接收分析任务"""
|
||||
global _currently_processing
|
||||
|
||||
data = request.get_json(silent=True)
|
||||
if not data:
|
||||
return jsonify({"error": "Invalid JSON"}), 400
|
||||
|
||||
task_id = data.get('task_id')
|
||||
video_url = data.get('video_url')
|
||||
webhook_url = data.get('webhook_url')
|
||||
|
||||
if not task_id or not video_url or not webhook_url:
|
||||
return jsonify({"error": "缺少必填字段: task_id, video_url, webhook_url"}), 400
|
||||
|
||||
logger.info(f"[task_id={task_id}] 收到任务: {video_url}")
|
||||
|
||||
# 并发控制
|
||||
with _current_task_lock:
|
||||
if _currently_processing:
|
||||
logger.warning(f"[task_id={task_id}] 队列已满 (当前有任务处理中),返回 429")
|
||||
return jsonify({"error": "Queue full", "retry_after": 60}), 429
|
||||
_currently_processing = True
|
||||
|
||||
# 异步处理
|
||||
def _process():
|
||||
global _currently_processing
|
||||
try:
|
||||
orch = get_orchestrator()
|
||||
orch.process_task(data)
|
||||
except Exception as e:
|
||||
logger.error(f"[task_id={task_id}] 处理异常: {e}", exc_info=True)
|
||||
finally:
|
||||
with _current_task_lock:
|
||||
_currently_processing = False
|
||||
|
||||
thread = threading.Thread(target=_process, daemon=True, name=f'task-{task_id}')
|
||||
thread.start()
|
||||
|
||||
return jsonify({"status": "accepted", "task_id": task_id}), 202
|
||||
|
||||
|
||||
@api_bp.route('/health', methods=['GET'])
|
||||
def health():
|
||||
"""健康检查"""
|
||||
global _currently_processing
|
||||
orch = get_orchestrator()
|
||||
healthy = orch.health_check_all()
|
||||
if not healthy:
|
||||
return jsonify({
|
||||
"status": "unavailable",
|
||||
"healthy_models": [],
|
||||
"processing": _currently_processing
|
||||
}), 503
|
||||
return jsonify({
|
||||
"status": "ok",
|
||||
"healthy_models": [a.provider_name for a in healthy],
|
||||
"processing": _currently_processing
|
||||
}), 200
|
||||
Reference in New Issue
Block a user