增加服务首页celery相关监控
This commit is contained in:
+145
-1
@@ -560,6 +560,150 @@ def create_app() -> FastAPI:
|
|||||||
async def health():
|
async def health():
|
||||||
return {"status": "ok"}
|
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)
|
@application.get("/internal/decrypt-data", response_class=HTMLResponse)
|
||||||
async def decrypt_data_page():
|
async def decrypt_data_page():
|
||||||
html_content = """
|
html_content = """
|
||||||
@@ -701,7 +845,7 @@ a:hover{text-decoration:underline}
|
|||||||
<div class="cards">
|
<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-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/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 class="card"><h3><a href="/internal/decrypt-data">解密数据</a></h3><p>数据解密</p></div>
|
||||||
</div>
|
</div>
|
||||||
</body></html>"""
|
</body></html>"""
|
||||||
|
|||||||
Reference in New Issue
Block a user