增加服务首页celery相关监控

This commit is contained in:
2026-06-17 15:51:12 +08:00
parent 4114ff1c16
commit 4bd150e32f
+145 -1
View File
@@ -560,6 +560,150 @@ def create_app() -> FastAPI:
async def health():
return {"status": "ok"}
@application.get("/internal/status", response_class=HTMLResponse)
async def status_page():
from app.tasks.celery_app import celery_app
from app.config import settings
celery_status = "unknown"
celery_error = ""
redis_status = "unknown"
redis_error = ""
try:
if celery_app:
inspect = celery_app.control.inspect()
try:
workers = inspect.stats()
if workers:
celery_status = "running"
else:
celery_status = "no_workers"
except Exception as e:
celery_status = "error"
celery_error = str(e)
else:
celery_status = "disabled"
except Exception as e:
celery_status = "error"
celery_error = str(e)
try:
if settings.REDIS_URL:
import redis
r = redis.from_url(settings.REDIS_URL)
r.ping()
redis_status = "connected"
else:
redis_status = "disabled"
except Exception as e:
redis_status = "disconnected"
redis_error = str(e)
def get_celery_text(status):
if status == 'running':
return '运行中'
elif status == 'no_workers':
return '无可用 Worker'
elif status == 'disabled':
return '已禁用'
elif status == 'error':
return '连接失败'
else:
return '未知'
def get_redis_text(status):
if status == 'connected':
return '已连接'
elif status == 'disabled':
return '已禁用'
elif status == 'disconnected':
return '未连接'
else:
return '未知'
celery_text = get_celery_text(celery_status)
redis_text = get_redis_text(redis_status)
celery_error_html = f'<div class="error-message">错误: {celery_error}</div>' if celery_error else ''
redis_error_html = f'<div class="error-message">错误: {redis_error}</div>' if redis_error else ''
html_content = f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>服务状态监控</title>
<style>
body {{ font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; background: #f5f6fa; }}
h1 {{ color: #1a1a2e; font-size: 28px; margin-bottom: 8px; }}
h1 span {{ color: #6366f1; }}
.status-card {{ background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; margin-bottom: 16px; }}
.status-card h3 {{ margin: 0 0 12px; font-size: 16px; color: #1e293b; }}
.status-indicator {{ display: inline-flex; align-items: center; gap: 8px; }}
.status-dot {{ width: 10px; height: 10px; border-radius: 50%; }}
.status-dot.running {{ background: #22c55e; box-shadow: 0 0 8px rgba(34, 197, 94, 0.5); }}
.status-dot.connected {{ background: #22c55e; box-shadow: 0 0 8px rgba(34, 197, 94, 0.5); }}
.status-dot.error {{ background: #dc2626; box-shadow: 0 0 8px rgba(220, 38, 38, 0.5); }}
.status-dot.disabled {{ background: #94a3b8; }}
.status-dot.unknown {{ background: #f59e0b; }}
.status-dot.no_workers {{ background: #f59e0b; }}
.status-dot.disconnected {{ background: #dc2626; }}
.status-text {{ font-weight: 600; }}
.status-text.running, .status-text.connected {{ color: #16a34a; }}
.status-text.error, .status-text.disconnected {{ color: #dc2626; }}
.status-text.disabled {{ color: #64748b; }}
.status-text.unknown, .status-text.no_workers {{ color: #d97706; }}
.error-message {{ margin-top: 8px; padding: 8px 12px; background: #fef2f2; border-radius: 6px; font-size: 13px; color: #dc2626; word-break: break-all; }}
.info-box {{ margin-top: 12px; padding: 12px; background: #f1f5f9; border-radius: 8px; font-size: 13px; color: #64748b; }}
.back-link {{ display: inline-block; margin-top: 20px; color: #6366f1; text-decoration: none; font-weight: 600; }}
.back-link:hover {{ text-decoration: underline; }}
.version {{ font-size: 13px; color: #94a3b8; margin-top: 4px; }}
</style>
</head>
<body>
<h1>服务状态<span>.</span></h1>
<p class="version">版本 v{settings.APP_VERSION}</p>
<div class="status-card">
<h3>Celery 任务队列</h3>
<div class="status-indicator">
<div class="status-dot {celery_status}"></div>
<span class="status-text {celery_status}">{celery_text}</span>
</div>
{celery_error_html}
<div class="info-box">
<strong>说明:</strong> Celery 用于异步处理 AI 生成任务、轮询任务和下载任务。如果显示"无可用 Worker",请启动 Celery worker。
</div>
</div>
<div class="status-card">
<h3>Redis 缓存</h3>
<div class="status-indicator">
<div class="status-dot {redis_status}"></div>
<span class="status-text {redis_status}">{redis_text}</span>
</div>
{redis_error_html}
<div class="info-box">
<strong>说明:</strong> Redis 用于 Celery 消息队列、任务状态存储和缓存。
</div>
</div>
<div class="status-card">
<h3>数据库连接</h3>
<div class="status-indicator">
<div class="status-dot connected"></div>
<span class="status-text connected">已连接</span>
</div>
<div class="info-box">
<strong>说明:</strong> PostgreSQL 数据库已连接。
</div>
</div>
<a href="/internal/" class="back-link">← 返回首页</a>
</body>
</html>"""
return HTMLResponse(content=html_content)
@application.get("/internal/decrypt-data", response_class=HTMLResponse)
async def decrypt_data_page():
html_content = """
@@ -701,7 +845,7 @@ a:hover{text-decoration:underline}
<div class="cards">
<div class="card"><h3><a href="/internal/api-docs">API 文档</a></h3><p>Swagger UI 交互式文档</p></div>
<div class="card"><h3><a href="/internal/api-redoc">ReDoc</a></h3><p>ReDoc 格式文档</p></div>
<div class="card"><h3><a href="/internal/health">健康检查</a></h3><p>服务状态</p></div>
<div class="card"><h3><a href="/internal/status">服务状态</a></h3><p>Celery/Redis 监控</p></div>
<div class="card"><h3><a href="/internal/decrypt-data">解密数据</a></h3><p>数据解密</p></div>
</div>
</body></html>"""