fix docker error handling

fix websocket routes
Add timezone variable in code
changed the env.example to suit
This commit is contained in:
Muhammad Ibrahim
2025-11-06 22:08:00 +00:00
parent 913976b7f6
commit a8eb3ec21c
6 changed files with 228 additions and 40 deletions

View File

@@ -3,6 +3,7 @@
const WebSocket = require("ws");
const url = require("node:url");
const { get_current_time } = require("../utils/timezone");
// Connection registry by api_id
const apiIdToSocket = new Map();
@@ -49,7 +50,29 @@ function init(server, prismaClient) {
wss.handleUpgrade(request, socket, head, (ws) => {
ws.on("message", (message) => {
// Echo back for Bull Board WebSocket
ws.send(message);
try {
ws.send(message);
} catch (err) {
// Ignore send errors (connection may be closed)
}
});
ws.on("error", (err) => {
// Handle WebSocket errors gracefully for Bull Board
if (
err.code === "WS_ERR_INVALID_CLOSE_CODE" ||
err.code === "ECONNRESET" ||
err.code === "EPIPE"
) {
// These are expected errors, just log quietly
console.log("[bullboard-ws] connection error:", err.code);
} else {
console.error("[bullboard-ws] error:", err.message || err);
}
});
ws.on("close", () => {
// Connection closed, no action needed
});
});
return;
@@ -117,7 +140,57 @@ function init(server, prismaClient) {
}
});
ws.on("close", () => {
ws.on("error", (err) => {
// Handle WebSocket errors gracefully without crashing
// Common errors: invalid close codes (1006), connection resets, etc.
if (
err.code === "WS_ERR_INVALID_CLOSE_CODE" ||
err.message?.includes("invalid status code 1006") ||
err.message?.includes("Invalid WebSocket frame")
) {
// 1006 is a special close code indicating abnormal closure
// It cannot be sent in a close frame, but can occur when connection is lost
console.log(
`[agent-ws] connection error for ${apiId} (abnormal closure):`,
err.message || err.code,
);
} else if (
err.code === "ECONNRESET" ||
err.code === "EPIPE" ||
err.message?.includes("read ECONNRESET")
) {
// Connection reset errors are common and expected
console.log(
`[agent-ws] connection reset for ${apiId}`,
);
} else {
// Log other errors for debugging
console.error(
`[agent-ws] error for ${apiId}:`,
err.message || err.code || err,
);
}
// Clean up connection on error
const existing = apiIdToSocket.get(apiId);
if (existing === ws) {
apiIdToSocket.delete(apiId);
connectionMetadata.delete(apiId);
// Notify subscribers of disconnection
notifyConnectionChange(apiId, false);
}
// Try to close the connection gracefully if still open
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
try {
ws.close(1000); // Normal closure
} catch {
// Ignore errors when closing
}
}
});
ws.on("close", (code, reason) => {
const existing = apiIdToSocket.get(apiId);
if (existing === ws) {
apiIdToSocket.delete(apiId);
@@ -126,7 +199,7 @@ function init(server, prismaClient) {
notifyConnectionChange(apiId, false);
}
console.log(
`[agent-ws] disconnected api_id=${apiId} total=${apiIdToSocket.size}`,
`[agent-ws] disconnected api_id=${apiId} code=${code} reason=${reason || "none"} total=${apiIdToSocket.size}`,
);
});
@@ -314,7 +387,7 @@ async function handleDockerStatusEvent(apiId, message) {
status: status,
state: status,
updated_at: new Date(timestamp || Date.now()),
last_checked: new Date(),
last_checked: get_current_time(),
},
});

View File

@@ -139,15 +139,13 @@ class DockerImageUpdateCheck {
console.log("🐳 Starting Docker image update check...");
try {
// Get all Docker images that have a digest and repository
// Get all Docker images that have a digest
// Note: repository is required (non-nullable) in schema, so we don't need to check it
const images = await prisma.docker_images.findMany({
where: {
digest: {
not: null,
},
repository: {
not: null,
},
},
include: {
docker_image_updates: true,

View File

@@ -3,6 +3,7 @@ const { redis, redisConnection } = require("./shared/redis");
const { prisma } = require("./shared/prisma");
const agentWs = require("../agentWs");
const { v4: uuidv4 } = require("uuid");
const { get_current_time } = require("../../utils/timezone");
// Import automation classes
const GitHubUpdateCheck = require("./githubUpdateCheck");
@@ -216,8 +217,8 @@ class QueueManager {
api_id: api_id,
status: "active",
attempt_number: job.attemptsMade + 1,
created_at: new Date(),
updated_at: new Date(),
created_at: get_current_time(),
updated_at: get_current_time(),
},
});
console.log(`📝 Logged job to job_history: ${job.id} (${type})`);
@@ -257,8 +258,8 @@ class QueueManager {
where: { job_id: job.id },
data: {
status: "completed",
completed_at: new Date(),
updated_at: new Date(),
completed_at: get_current_time(),
updated_at: get_current_time(),
},
});
console.log(`✅ Marked job as completed in job_history: ${job.id}`);
@@ -271,8 +272,8 @@ class QueueManager {
data: {
status: "failed",
error_message: error.message,
completed_at: new Date(),
updated_at: new Date(),
completed_at: get_current_time(),
updated_at: get_current_time(),
},
});
console.log(`❌ Marked job as failed in job_history: ${job.id}`);