perf(runtime): switch socketio to eventlet and optimize asset chunk caching
This commit is contained in:
74
app.py
74
app.py
@@ -14,6 +14,7 @@ from __future__ import annotations
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
@@ -86,18 +87,38 @@ if not app.config.get("SECRET_KEY"):
|
||||
cors_origins = os.environ.get("CORS_ALLOWED_ORIGINS", "").strip()
|
||||
cors_allowed = [o.strip() for o in cors_origins.split(",") if o.strip()] if cors_origins else []
|
||||
|
||||
socketio = SocketIO(
|
||||
app,
|
||||
cors_allowed_origins=cors_allowed if cors_allowed else None,
|
||||
async_mode="threading",
|
||||
ping_timeout=60,
|
||||
ping_interval=25,
|
||||
logger=False,
|
||||
engineio_logger=False,
|
||||
)
|
||||
_socketio_preferred_mode = (os.environ.get("SOCKETIO_ASYNC_MODE", "eventlet") or "").strip().lower()
|
||||
if _socketio_preferred_mode in {"", "auto"}:
|
||||
_socketio_preferred_mode = None
|
||||
|
||||
_socketio_fallback_reason = None
|
||||
try:
|
||||
socketio = SocketIO(
|
||||
app,
|
||||
cors_allowed_origins=cors_allowed if cors_allowed else None,
|
||||
async_mode=_socketio_preferred_mode,
|
||||
ping_timeout=60,
|
||||
ping_interval=25,
|
||||
logger=False,
|
||||
engineio_logger=False,
|
||||
)
|
||||
except Exception as socketio_error:
|
||||
_socketio_fallback_reason = str(socketio_error)
|
||||
socketio = SocketIO(
|
||||
app,
|
||||
cors_allowed_origins=cors_allowed if cors_allowed else None,
|
||||
async_mode="threading",
|
||||
ping_timeout=60,
|
||||
ping_interval=25,
|
||||
logger=False,
|
||||
engineio_logger=False,
|
||||
)
|
||||
|
||||
init_logging(log_level=config.LOG_LEVEL, log_file=config.LOG_FILE)
|
||||
logger = get_logger("app")
|
||||
if _socketio_fallback_reason:
|
||||
logger.warning(f"[SocketIO] 初始化失败,已回退 threading 模式: {_socketio_fallback_reason}")
|
||||
logger.info(f"[SocketIO] 当前 async_mode: {socketio.async_mode}")
|
||||
init_runtime(socketio=socketio, logger=logger)
|
||||
|
||||
_API_DIAGNOSTIC_LOG = str(os.environ.get("API_DIAGNOSTIC_LOG", "0")).strip().lower() in {
|
||||
@@ -114,6 +135,9 @@ def _is_api_or_health_path(path: str) -> bool:
|
||||
return raw.startswith("/api/") or raw.startswith("/yuyx/api/") or raw == "/health"
|
||||
|
||||
|
||||
_HASHED_STATIC_ASSET_RE = re.compile(r".*-[a-z0-9_-]{8,}\.(?:js|css|woff2?|ttf|svg|png|jpe?g|webp)$", re.IGNORECASE)
|
||||
|
||||
|
||||
# 初始化安全中间件(需在其他中间件/Blueprint 之前注册)
|
||||
init_security_middleware(app)
|
||||
|
||||
@@ -226,10 +250,15 @@ def serve_static(filename):
|
||||
if not is_safe_path("static", filename):
|
||||
return jsonify({"error": "非法路径"}), 403
|
||||
|
||||
cache_ttl = 3600
|
||||
lowered = filename.lower()
|
||||
if "/assets/" in lowered or lowered.endswith((".js", ".css", ".woff", ".woff2", ".ttf", ".svg")):
|
||||
is_asset_file = "/assets/" in lowered or lowered.endswith((".js", ".css", ".woff", ".woff2", ".ttf", ".svg"))
|
||||
is_hashed_asset = bool(_HASHED_STATIC_ASSET_RE.match(lowered))
|
||||
|
||||
cache_ttl = 3600
|
||||
if is_asset_file:
|
||||
cache_ttl = 604800 # 7天
|
||||
if is_hashed_asset:
|
||||
cache_ttl = 31536000 # 365天
|
||||
|
||||
if request.args.get("v"):
|
||||
cache_ttl = max(cache_ttl, 604800)
|
||||
@@ -247,7 +276,12 @@ def serve_static(filename):
|
||||
pass
|
||||
|
||||
response.headers.setdefault("Vary", "Accept-Encoding")
|
||||
response.headers["Cache-Control"] = f"public, max-age={cache_ttl}"
|
||||
if is_hashed_asset:
|
||||
response.headers["Cache-Control"] = f"public, max-age={cache_ttl}, immutable"
|
||||
elif is_asset_file:
|
||||
response.headers["Cache-Control"] = f"public, max-age={cache_ttl}, stale-while-revalidate=60"
|
||||
else:
|
||||
response.headers["Cache-Control"] = f"public, max-age={cache_ttl}"
|
||||
return response
|
||||
|
||||
|
||||
@@ -416,10 +450,12 @@ if __name__ == "__main__":
|
||||
_init_screenshot_worker_pool()
|
||||
_warmup_api_connection()
|
||||
|
||||
socketio.run(
|
||||
app,
|
||||
host=config.SERVER_HOST,
|
||||
port=config.SERVER_PORT,
|
||||
debug=config.DEBUG,
|
||||
allow_unsafe_werkzeug=True,
|
||||
)
|
||||
run_kwargs = {
|
||||
"host": config.SERVER_HOST,
|
||||
"port": config.SERVER_PORT,
|
||||
"debug": config.DEBUG,
|
||||
}
|
||||
if str(socketio.async_mode) == "threading":
|
||||
run_kwargs["allow_unsafe_werkzeug"] = True
|
||||
|
||||
socketio.run(app, **run_kwargs)
|
||||
|
||||
Reference in New Issue
Block a user