hangmu-docker / patch_backend.mjs
bep40's picture
VERSION_ID ổn định ('v6') — hết 'Có bản mới' giả mỗi lần backend restart (uuid đổi mỗi process)
9004c36 verified
Raw History Blame
2.43 kB
/* Patch backend.py:
1) Thêm /api/log + /api/logs để nhận client-side errors
(React crash, WebGL, promise rejection) từ ErrorBoundary / window.onerror.
2) VERSION_ID ổn định: trước đây `uuid.uuid4().hex[:8]` đổi mỗi lần Space
restart → client so sánh version.json thấy khác → tưởng "Có bản mới"
và tự reload liên tục. Giờ dùng hằng số "v6" khớp cache-bust bundle,
chỉ đổi khi ta chủ động deploy bản mới.
Chạy trong Dockerfile build stage (backend.py được COPY vào build stage).
Nếu pattern không khớp -> exit(1). */
import fs from 'node:fs'
const path = 'backend.py'
let s = fs.readFileSync(path, 'utf8')
// --- VERSION_ID ổn định (khớp ?v=6 cache-bust) ---
const oldVer = 'VERSION_ID = uuid.uuid4().hex[:8]'
if (!s.includes(oldVer)) {
console.error('PATCH FAILED: VERSION_ID marker not found')
process.exit(1)
}
s = s.replace(oldVer, 'VERSION_ID = "v6"')
// IMPORTANT: phải chèn TRƯỚC catch-all @app.get("/{path:path}") (serve_static) —
// nếu chèn sau, FastAPI match route theo thứ tự đăng ký → GET /api/logs bị
// catch-all nuốt, trả index.html thay vì JSON (không đọc được client errors).
const markers = [
'@app.get("/{path:path}")', // nơi lý tưởng: chèn ngay trước catch-all
'if __name__ == "__main__":', // fallback cũ (chỉ dùng nếu không tìm thấy catch-all)
]
let idx = -1
let used = -1
for (let i = 0; i < markers.length; i++) {
const m = markers[i]
const at = s.indexOf(m)
if (at !== -1) {
// tìm đầu dòng để chèn sạch sẽ
const lineStart = s.lastIndexOf('\n', at) + 1
idx = lineStart
used = i
break
}
}
if (idx === -1) {
console.error('PATCH FAILED: marker not found')
process.exit(1)
}
const inject = `# ============ Client error log (từ ErrorBoundary / window.onerror) ============
_client_logs = []
@app.post("/api/log")
async def api_log(req: dict):
entry = {"at": time.time()}
if isinstance(req, dict):
entry.update(req)
_client_logs.append(entry)
del _client_logs[:-400]
return {"ok": True}
@app.get("/api/logs")
async def api_logs():
return {"logs": _client_logs[-200:]}
`
s = s.slice(0, idx) + inject + s.slice(idx)
fs.writeFileSync(path, s)
console.log(`patched backend.py ok: VERSION_ID=v6, /api/log + /api/logs (marker [${used}])`)