perf: add compression and caching for faster public access
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 2m20s
Deploy Dashboard (Dev) / deploy-dev (push) Successful in 2m20s
Optimizations to reduce latency over Tailscale tunnel: - Add GZip middleware for 70% bandwidth reduction (480KB → ~150KB) - Cache static assets with immutable headers (1 year) - Remove 500ms blocking CPU interval in system stats These changes significantly improve dashboard load time over public network. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
from fastapi import FastAPI, Depends, Request
|
from fastapi import FastAPI, Depends, Request
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from fastapi.middleware.gzip import GZipMiddleware
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from slowapi import Limiter
|
from slowapi import Limiter
|
||||||
from slowapi.util import get_remote_address
|
from slowapi.util import get_remote_address
|
||||||
@@ -31,6 +32,9 @@ app.add_middleware(
|
|||||||
allow_headers=["Authorization", "Content-Type"],
|
allow_headers=["Authorization", "Content-Type"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Compress responses (static files and API responses)
|
||||||
|
app.add_middleware(GZipMiddleware, minimum_size=1000)
|
||||||
|
|
||||||
@app.exception_handler(RateLimitExceeded)
|
@app.exception_handler(RateLimitExceeded)
|
||||||
async def rate_limit_handler(request: Request, exc: RateLimitExceeded):
|
async def rate_limit_handler(request: Request, exc: RateLimitExceeded):
|
||||||
return JSONResponse(status_code=429, content={"detail": "Too many requests, try again later"})
|
return JSONResponse(status_code=429, content={"detail": "Too many requests, try again later"})
|
||||||
@@ -43,6 +47,11 @@ async def security_headers(request: Request, call_next):
|
|||||||
response.headers["X-XSS-Protection"] = "1; mode=block"
|
response.headers["X-XSS-Protection"] = "1; mode=block"
|
||||||
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
|
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
|
||||||
response.headers["Content-Security-Policy"] = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' wss: ws:; frame-ancestors 'none'"
|
response.headers["Content-Security-Policy"] = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' wss: ws:; frame-ancestors 'none'"
|
||||||
|
|
||||||
|
# Cache static assets with hashed filenames (Vite generates these)
|
||||||
|
if request.url.path.startswith("/assets/"):
|
||||||
|
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# Audit logger
|
# Audit logger
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ def system_stats():
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
mem = psutil.virtual_memory()
|
mem = psutil.virtual_memory()
|
||||||
cpu_pct = psutil.cpu_percent(interval=0.5)
|
cpu_pct = psutil.cpu_percent(interval=0) # Non-blocking, uses cached value
|
||||||
load_1, load_5, load_15 = psutil.getloadavg()
|
load_1, load_5, load_15 = psutil.getloadavg()
|
||||||
uptime_s = time.time() - psutil.boot_time()
|
uptime_s = time.time() - psutil.boot_time()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user