mirror of
https://github.com/AgentDeskAI/browser-tools-mcp.git
synced 2025-06-27 00:41:26 +00:00
bugfix: Implement Graceful WebSocket Server Shutdown Mechanism
- Added shutdown method to BrowserConnector for controlled WebSocket server closure - Improved process signal handling for SIGINT and SIGTERM - Updated Chrome extension to handle server shutdown signal - Bumped package versions to 1.1.0 for browser-tools-mcp and browser-tools-server
This commit is contained in:
parent
04bbbdaf34
commit
e55410bc5c
4
browser-tools-mcp/package-lock.json
generated
4
browser-tools-mcp/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@agentdeskai/browser-tools-mcp",
|
"name": "@agentdeskai/browser-tools-mcp",
|
||||||
"version": "1.0.11",
|
"version": "1.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@agentdeskai/browser-tools-mcp",
|
"name": "@agentdeskai/browser-tools-mcp",
|
||||||
"version": "1.0.11",
|
"version": "1.1.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.4.1",
|
"@modelcontextprotocol/sdk": "^1.4.1",
|
||||||
|
@ -667,6 +667,47 @@ export class BrowserConnector {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add shutdown method
|
||||||
|
public shutdown() {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
console.log("Shutting down WebSocket server...");
|
||||||
|
|
||||||
|
// Send close message to client if connection is active
|
||||||
|
if (this.activeConnection && this.activeConnection.readyState === WebSocket.OPEN) {
|
||||||
|
console.log("Notifying client to close connection...");
|
||||||
|
try {
|
||||||
|
this.activeConnection.send(JSON.stringify({ type: "server-shutdown" }));
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error sending shutdown message to client:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a timeout to force close after 2 seconds
|
||||||
|
const forceCloseTimeout = setTimeout(() => {
|
||||||
|
console.log("Force closing connections after timeout...");
|
||||||
|
if (this.activeConnection) {
|
||||||
|
this.activeConnection.terminate(); // Force close the connection
|
||||||
|
this.activeConnection = null;
|
||||||
|
}
|
||||||
|
this.wss.close();
|
||||||
|
resolve();
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
// Close active WebSocket connection if exists
|
||||||
|
if (this.activeConnection) {
|
||||||
|
this.activeConnection.close(1000, "Server shutting down");
|
||||||
|
this.activeConnection = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close WebSocket server
|
||||||
|
this.wss.close(() => {
|
||||||
|
clearTimeout(forceCloseTimeout);
|
||||||
|
console.log("WebSocket server closed gracefully");
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the server creation before BrowserConnector instantiation
|
// Move the server creation before BrowserConnector instantiation
|
||||||
@ -677,10 +718,41 @@ const server = app.listen(PORT, () => {
|
|||||||
// Initialize the browser connector with the existing app AND server
|
// Initialize the browser connector with the existing app AND server
|
||||||
const browserConnector = new BrowserConnector(app, server);
|
const browserConnector = new BrowserConnector(app, server);
|
||||||
|
|
||||||
// Handle shutdown gracefully
|
// Handle shutdown gracefully with improved error handling
|
||||||
process.on("SIGINT", () => {
|
process.on("SIGINT", async () => {
|
||||||
server.close(() => {
|
console.log("\nReceived SIGINT signal. Starting graceful shutdown...");
|
||||||
console.log("Server shut down");
|
|
||||||
|
try {
|
||||||
|
// First shutdown WebSocket connections
|
||||||
|
await browserConnector.shutdown();
|
||||||
|
|
||||||
|
// Then close the HTTP server
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
server.close((err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error closing HTTP server:", err);
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
console.log("HTTP server closed successfully");
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clear all logs
|
||||||
|
clearAllLogs();
|
||||||
|
|
||||||
|
console.log("Shutdown completed successfully");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error during shutdown:", error);
|
||||||
|
// Force exit in case of error
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Also handle SIGTERM
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
console.log("\nReceived SIGTERM signal");
|
||||||
|
process.emit("SIGINT");
|
||||||
});
|
});
|
||||||
|
4
browser-tools-server/package-lock.json
generated
4
browser-tools-server/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@agentdeskai/browser-tools-server",
|
"name": "@agentdeskai/browser-tools-server",
|
||||||
"version": "1.0.5",
|
"version": "1.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@agentdeskai/browser-tools-server",
|
"name": "@agentdeskai/browser-tools-server",
|
||||||
"version": "1.0.5",
|
"version": "1.1.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.4.1",
|
"@modelcontextprotocol/sdk": "^1.4.1",
|
||||||
|
@ -536,6 +536,18 @@ function setupWebSocket() {
|
|||||||
const message = JSON.parse(event.data);
|
const message = JSON.parse(event.data);
|
||||||
console.log("Chrome Extension: Received WebSocket message:", message);
|
console.log("Chrome Extension: Received WebSocket message:", message);
|
||||||
|
|
||||||
|
if (message.type === "server-shutdown") {
|
||||||
|
console.log("Chrome Extension: Received server shutdown signal");
|
||||||
|
// Clear any reconnection attempts
|
||||||
|
if (wsReconnectTimeout) {
|
||||||
|
clearTimeout(wsReconnectTimeout);
|
||||||
|
wsReconnectTimeout = null;
|
||||||
|
}
|
||||||
|
// Close the connection gracefully
|
||||||
|
ws.close(1000, "Server shutting down");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (message.type === "take-screenshot") {
|
if (message.type === "take-screenshot") {
|
||||||
console.log("Chrome Extension: Taking screenshot...");
|
console.log("Chrome Extension: Taking screenshot...");
|
||||||
// Capture screenshot of the current tab
|
// Capture screenshot of the current tab
|
||||||
@ -574,10 +586,7 @@ function setupWebSocket() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error("Chrome Extension: Error processing WebSocket message:", error);
|
||||||
"Chrome Extension: Error processing WebSocket message:",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -589,11 +598,17 @@ function setupWebSocket() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onclose = () => {
|
ws.onclose = (event) => {
|
||||||
console.log(
|
console.log(
|
||||||
"Chrome Extension: WebSocket disconnected, attempting to reconnect..."
|
`Chrome Extension: WebSocket disconnected (${event.code}: ${event.reason})`
|
||||||
);
|
);
|
||||||
|
// Only attempt to reconnect if it wasn't a server shutdown
|
||||||
|
if (event.reason !== "Server shutting down") {
|
||||||
|
console.log("Chrome Extension: Attempting to reconnect...");
|
||||||
wsReconnectTimeout = setTimeout(setupWebSocket, WS_RECONNECT_DELAY);
|
wsReconnectTimeout = setTimeout(setupWebSocket, WS_RECONNECT_DELAY);
|
||||||
|
} else {
|
||||||
|
console.log("Chrome Extension: Server shutdown detected, not reconnecting");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onerror = (error) => {
|
ws.onerror = (error) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user