feat: keep containers alive for 60s of inactivity instead of killing them on disconnect
This commit is contained in:
parent
09b3cf1862
commit
01fb3ab921
@ -34,6 +34,9 @@ import {
|
|||||||
saveFileRL,
|
saveFileRL,
|
||||||
} from "./ratelimit";
|
} from "./ratelimit";
|
||||||
|
|
||||||
|
// The amount of time in ms that a container will stay alive without a hearbeat.
|
||||||
|
const CONTAINER_TIMEOUT = 60_000;
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const app: Express = express();
|
const app: Express = express();
|
||||||
@ -161,7 +164,7 @@ io.on("connection", async (socket) => {
|
|||||||
try {
|
try {
|
||||||
// Start a new container if the container doesn't exist or it timed out.
|
// Start a new container if the container doesn't exist or it timed out.
|
||||||
if (!containers[data.sandboxId] || !(await containers[data.sandboxId].isRunning())) {
|
if (!containers[data.sandboxId] || !(await containers[data.sandboxId].isRunning())) {
|
||||||
containers[data.sandboxId] = await Sandbox.create({ timeoutMs: 1200_000 });
|
containers[data.sandboxId] = await Sandbox.create({ timeoutMs: CONTAINER_TIMEOUT });
|
||||||
console.log("Created container ", data.sandboxId);
|
console.log("Created container ", data.sandboxId);
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@ -198,6 +201,17 @@ io.on("connection", async (socket) => {
|
|||||||
|
|
||||||
socket.emit("loaded", sandboxFiles.files);
|
socket.emit("loaded", sandboxFiles.files);
|
||||||
|
|
||||||
|
socket.on("heartbeat", async () => {
|
||||||
|
try {
|
||||||
|
// This keeps the container alive for another CONTAINER_TIMEOUT seconds.
|
||||||
|
// The E2B docs are unclear, but the timeout is relative to the time of this method call.
|
||||||
|
await containers[data.sandboxId].setTimeout(CONTAINER_TIMEOUT);
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error("Error setting timeout:", e);
|
||||||
|
io.emit("error", `Error: set timeout. ${e.message ?? e}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on("getFile", (fileId: string, callback) => {
|
socket.on("getFile", (fileId: string, callback) => {
|
||||||
console.log(fileId);
|
console.log(fileId);
|
||||||
try {
|
try {
|
||||||
@ -656,25 +670,6 @@ io.on("connection", async (socket) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.isOwner && connections[data.sandboxId] <= 0) {
|
if (data.isOwner && connections[data.sandboxId] <= 0) {
|
||||||
await Promise.all(
|
|
||||||
Object.entries(terminals).map(async ([key, terminal]) => {
|
|
||||||
await terminal.close();
|
|
||||||
delete terminals[key];
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
await lockManager.acquireLock(data.sandboxId, async () => {
|
|
||||||
try {
|
|
||||||
if (containers[data.sandboxId]) {
|
|
||||||
await containers[data.sandboxId].kill();
|
|
||||||
delete containers[data.sandboxId];
|
|
||||||
console.log("Closed container", data.sandboxId);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error closing container ", data.sandboxId, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.broadcast.emit(
|
socket.broadcast.emit(
|
||||||
"disableAccess",
|
"disableAccess",
|
||||||
"The sandbox owner has disconnected."
|
"The sandbox owner has disconnected."
|
||||||
|
@ -59,6 +59,13 @@ export default function CodeEditor({
|
|||||||
}
|
}
|
||||||
}, [socket, userData.id, sandboxData.id, setUserAndSandboxId])
|
}, [socket, userData.id, sandboxData.id, setUserAndSandboxId])
|
||||||
|
|
||||||
|
// This heartbeat is critical to preventing the E2B sandbox from timing out
|
||||||
|
useEffect(() => {
|
||||||
|
// 10000 ms = 10 seconds
|
||||||
|
const interval = setInterval(() => socket?.emit("heartbeat"), 10000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [socket]);
|
||||||
|
|
||||||
//Preview Button state
|
//Preview Button state
|
||||||
const [isPreviewCollapsed, setIsPreviewCollapsed] = useState(true)
|
const [isPreviewCollapsed, setIsPreviewCollapsed] = useState(true)
|
||||||
const [disableAccess, setDisableAccess] = useState({
|
const [disableAccess, setDisableAccess] = useState({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user