fix add error boundry
Browse files- lib/docker/manager.ts +0 -1
- lib/hf/storage.ts +8 -3
- server.ts +11 -2
lib/docker/manager.ts
CHANGED
|
@@ -191,7 +191,6 @@ async function performProvisioning(config: WorkspaceConfig): Promise<WorkspaceOp
|
|
| 191 |
} catch (e) {
|
| 192 |
log(`[WARN] Persistent profile restoration failed: ${e instanceof Error ? e.message : String(e)}. Proceeding with clean environment.`);
|
| 193 |
}
|
| 194 |
-
HFStorage.startAutoSave(300000); // 5m auto-save
|
| 195 |
|
| 196 |
// 1. Prepare Workspace Directory
|
| 197 |
const workspaceRoot = process.env.WORKSPACE_ROOT || path.join(/*turbopackIgnore: true*/ '/home/node/w');
|
|
|
|
| 191 |
} catch (e) {
|
| 192 |
log(`[WARN] Persistent profile restoration failed: ${e instanceof Error ? e.message : String(e)}. Proceeding with clean environment.`);
|
| 193 |
}
|
|
|
|
| 194 |
|
| 195 |
// 1. Prepare Workspace Directory
|
| 196 |
const workspaceRoot = process.env.WORKSPACE_ROOT || path.join(/*turbopackIgnore: true*/ '/home/node/w');
|
lib/hf/storage.ts
CHANGED
|
@@ -103,11 +103,16 @@ export class HFStorage {
|
|
| 103 |
}
|
| 104 |
|
| 105 |
/**
|
| 106 |
-
* Starts the periodic persistence interval.
|
| 107 |
*/
|
| 108 |
-
static
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
setInterval(async () => {
|
| 110 |
-
await this.syncToDataset((msg) => console.log(msg));
|
| 111 |
}, intervalMs);
|
| 112 |
}
|
| 113 |
}
|
|
|
|
| 103 |
}
|
| 104 |
|
| 105 |
/**
|
| 106 |
+
* Starts the periodic persistence interval (Singleton Heartbeat).
|
| 107 |
*/
|
| 108 |
+
private static autoSaveStarted = false;
|
| 109 |
+
static startAutoSave(intervalMs: number = 300000) {
|
| 110 |
+
if (this.autoSaveStarted) return;
|
| 111 |
+
this.autoSaveStarted = true;
|
| 112 |
+
|
| 113 |
+
console.log(`[HF:STORAGE] Persistence heartbeat initialized (Interval: ${intervalMs}ms)`);
|
| 114 |
setInterval(async () => {
|
| 115 |
+
await this.syncToDataset((msg) => console.log(msg)).catch(() => {});
|
| 116 |
}, intervalMs);
|
| 117 |
}
|
| 118 |
}
|
server.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import { createServer, IncomingMessage, ServerResponse } from "http";
|
| 2 |
import next from "next";
|
| 3 |
import { Server } from "socket.io";
|
|
@@ -14,6 +20,7 @@ import { Duplex } from "stream";
|
|
| 14 |
import { startAutoSleepCron } from "./lib/jobs/auto-sleep";
|
| 15 |
import { getNativeWorkspacePort, getAndroidPort, isNativeWorkspaceRunning, prewarmWorkspace, reconnectRunningWorkspaces, nativeProcesses } from "./lib/docker/manager";
|
| 16 |
import { initDb } from "./lib/db/schema";
|
|
|
|
| 17 |
import { ENV_CONFIG, validateEnvironment } from "./lib/env-config";
|
| 18 |
import httpProxy from "http-proxy";
|
| 19 |
|
|
@@ -151,7 +158,10 @@ app.prepare()
|
|
| 151 |
.catch(err => console.error("[BOOT] Database init failed:", err));
|
| 152 |
|
| 153 |
// 🛠️ Self-Healing: Reconnect to orphans from previous instance
|
| 154 |
-
reconnectRunningWorkspaces();
|
|
|
|
|
|
|
|
|
|
| 155 |
startAutoSleepCron();
|
| 156 |
|
| 157 |
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
|
|
@@ -179,7 +189,6 @@ app.prepare()
|
|
| 179 |
|
| 180 |
return proxy.web(req, res, { target: `http://127.0.0.1:${port}`, changeOrigin: true });
|
| 181 |
} else if (!pathname?.startsWith("/api/")) {
|
| 182 |
-
console.log(`[PROXY:DEBUG] Workspace ${id} not found in nativeProcesses. Available:`, Array.from(nativeProcesses.keys()));
|
| 183 |
// EXCLUSIVE FIX (April 2026): Prevent Next.js 404 fallthrough
|
| 184 |
// Only show for main workspace routes, let API routes pass to Next.js for provisioning.
|
| 185 |
res.writeHead(503, { 'Content-Type': 'text/html', 'Retry-After': '5' });
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* 🛰️ GLOBAL STABILIZATION (April 2026): Catch unhandled errors that cause HF Space restarts.
|
| 3 |
+
*/
|
| 4 |
+
process.on('uncaughtException', (err) => { console.error('[FATAL:EXCEPTION]', err); });
|
| 5 |
+
process.on('unhandledRejection', (reason) => { console.error('[FATAL:REJECTION]', reason); });
|
| 6 |
+
|
| 7 |
import { createServer, IncomingMessage, ServerResponse } from "http";
|
| 8 |
import next from "next";
|
| 9 |
import { Server } from "socket.io";
|
|
|
|
| 20 |
import { startAutoSleepCron } from "./lib/jobs/auto-sleep";
|
| 21 |
import { getNativeWorkspacePort, getAndroidPort, isNativeWorkspaceRunning, prewarmWorkspace, reconnectRunningWorkspaces, nativeProcesses } from "./lib/docker/manager";
|
| 22 |
import { initDb } from "./lib/db/schema";
|
| 23 |
+
import { HFStorage } from "./lib/hf/storage";
|
| 24 |
import { ENV_CONFIG, validateEnvironment } from "./lib/env-config";
|
| 25 |
import httpProxy from "http-proxy";
|
| 26 |
|
|
|
|
| 158 |
.catch(err => console.error("[BOOT] Database init failed:", err));
|
| 159 |
|
| 160 |
// 🛠️ Self-Healing: Reconnect to orphans from previous instance
|
| 161 |
+
reconnectRunningWorkspaces().catch(err => console.error("[BOOT] Reconnection failed:", err));
|
| 162 |
+
|
| 163 |
+
// 🛡️ Persistence: Global heartbeat (starts once)
|
| 164 |
+
HFStorage.startAutoSave(300000);
|
| 165 |
startAutoSleepCron();
|
| 166 |
|
| 167 |
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
|
|
|
|
| 189 |
|
| 190 |
return proxy.web(req, res, { target: `http://127.0.0.1:${port}`, changeOrigin: true });
|
| 191 |
} else if (!pathname?.startsWith("/api/")) {
|
|
|
|
| 192 |
// EXCLUSIVE FIX (April 2026): Prevent Next.js 404 fallthrough
|
| 193 |
// Only show for main workspace routes, let API routes pass to Next.js for provisioning.
|
| 194 |
res.writeHead(503, { 'Content-Type': 'text/html', 'Retry-After': '5' });
|