mcp-hub-009: Graceful backend failure — JSON-RPC error responses and session cleanup
This commit is contained in:
parent
050c63e8d3
commit
aa78585a45
3 changed files with 52 additions and 4 deletions
51
src/relay.js
51
src/relay.js
|
|
@ -3,9 +3,21 @@ const registry = require('./backend-registry');
|
||||||
|
|
||||||
const pendingRequests = new Map();
|
const pendingRequests = new Map();
|
||||||
|
|
||||||
function sendToBackend(serviceId, message, clientSessionId) {
|
function sendToBackend(serviceId, message, clientSessionId, sessions) {
|
||||||
const ws = registry.get(serviceId);
|
const ws = registry.get(serviceId);
|
||||||
if (!ws) return null;
|
if (!ws) {
|
||||||
|
if (sessions && message.id !== undefined && message.id !== null) {
|
||||||
|
const session = sessions.get(clientSessionId);
|
||||||
|
if (session) {
|
||||||
|
session.res.write('event: message\ndata: ' + JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: message.id,
|
||||||
|
error: { code: -32603, message: 'Backend unavailable' }
|
||||||
|
}) + '\n\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const requestId = uuidv4();
|
const requestId = uuidv4();
|
||||||
pendingRequests.set(requestId, { serviceId, clientSessionId });
|
pendingRequests.set(requestId, { serviceId, clientSessionId });
|
||||||
|
|
@ -53,4 +65,37 @@ function handleBackendMessage(serviceId, data, sessions) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { sendToBackend, handleBackendMessage };
|
function cleanupBackend(serviceId, sessions) {
|
||||||
|
// Clean up pending requests for this backend
|
||||||
|
for (const [requestId, pending] of pendingRequests) {
|
||||||
|
if (pending.serviceId === serviceId) {
|
||||||
|
const session = sessions.get(pending.clientSessionId);
|
||||||
|
if (session) {
|
||||||
|
// Write error notification event
|
||||||
|
session.res.write('event: message\ndata: ' + JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: null,
|
||||||
|
error: { code: -32603, message: 'Backend disconnected' }
|
||||||
|
}) + '\n\n');
|
||||||
|
}
|
||||||
|
pendingRequests.delete(requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up active SSE sessions for this backend
|
||||||
|
for (const [clientSessionId, session] of sessions) {
|
||||||
|
if (session.serviceId === serviceId) {
|
||||||
|
// Write final error event
|
||||||
|
session.res.write('event: message\ndata: ' + JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: null,
|
||||||
|
error: { code: -32603, message: 'Backend disconnected' }
|
||||||
|
}) + '\n\n');
|
||||||
|
// End the response
|
||||||
|
session.res.end();
|
||||||
|
sessions.delete(clientSessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { sendToBackend, handleBackendMessage, cleanupBackend };
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ router.post('/:serviceId/message', (req, res) => {
|
||||||
return res.status(502).json({ error: 'backend not connected' });
|
return res.status(502).json({ error: 'backend not connected' });
|
||||||
}
|
}
|
||||||
|
|
||||||
relay.sendToBackend(serviceId, req.body, sessionId);
|
relay.sendToBackend(serviceId, req.body, sessionId, sessions);
|
||||||
|
|
||||||
return res.status(202).json({ status: 'accepted' });
|
return res.status(202).json({ status: 'accepted' });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,9 @@ function setupWsServer(httpServer) {
|
||||||
if (pingTimer) clearInterval(pingTimer);
|
if (pingTimer) clearInterval(pingTimer);
|
||||||
if (authenticated && serviceId) {
|
if (authenticated && serviceId) {
|
||||||
registry.unregister(serviceId);
|
registry.unregister(serviceId);
|
||||||
|
const { cleanupBackend } = require('./relay');
|
||||||
|
const { sessions } = require('./routes/mcp-proxy');
|
||||||
|
cleanupBackend(serviceId, sessions);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue