feat: add fallback dummy socket run logic
This commit is contained in:
@@ -54,20 +54,23 @@ export const initializeRemoteBrowserForRecording = (userId: string): string => {
|
|||||||
* @category BrowserManagement-Controller
|
* @category BrowserManagement-Controller
|
||||||
*/
|
*/
|
||||||
export const createRemoteBrowserForRun = (userId: string): string => {
|
export const createRemoteBrowserForRun = (userId: string): string => {
|
||||||
const id = uuid();
|
if (!userId) {
|
||||||
|
logger.log('error', 'createRemoteBrowserForRun: Missing required parameter userId');
|
||||||
|
throw new Error('userId is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = uuid();
|
||||||
|
|
||||||
|
const slotReserved = browserPool.reserveBrowserSlot(id, userId, "run");
|
||||||
|
if (!slotReserved) {
|
||||||
|
logger.log('warn', `Cannot create browser for user ${userId}: no available slots`);
|
||||||
|
throw new Error('User has reached maximum browser limit');
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log('info', `createRemoteBrowserForRun: Reserved slot ${id} for user ${userId}`);
|
||||||
|
|
||||||
|
initializeBrowserAsync(id, userId);
|
||||||
|
|
||||||
createSocketConnectionForRun(
|
|
||||||
io.of(id),
|
|
||||||
async (socket: Socket) => {
|
|
||||||
try {
|
|
||||||
const browserSession = new RemoteBrowser(socket, userId, id);
|
|
||||||
await browserSession.initialize(userId);
|
|
||||||
browserPool.addRemoteBrowser(id, browserSession, userId, false, "run");
|
|
||||||
socket.emit('ready-for-run');
|
|
||||||
} catch (error: any) {
|
|
||||||
logger.error(`Error initializing browser: ${error.message}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return id;
|
return id;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -211,3 +214,87 @@ export const stopRunningInterpretation = async (userId: string) => {
|
|||||||
logger.log('error', 'Cannot stop interpretation: No active browser or generator.');
|
logger.log('error', 'Cannot stop interpretation: No active browser or generator.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initializeBrowserAsync = async (id: string, userId: string) => {
|
||||||
|
try {
|
||||||
|
const namespace = io.of(id);
|
||||||
|
let clientConnected = false;
|
||||||
|
let connectionTimeout: NodeJS.Timeout;
|
||||||
|
|
||||||
|
const waitForConnection = new Promise<Socket | null>((resolve) => {
|
||||||
|
namespace.on('connection', (socket: Socket) => {
|
||||||
|
clientConnected = true;
|
||||||
|
clearTimeout(connectionTimeout);
|
||||||
|
logger.log('info', `Frontend connected to browser ${id} via socket ${socket.id}`);
|
||||||
|
resolve(socket);
|
||||||
|
});
|
||||||
|
|
||||||
|
connectionTimeout = setTimeout(() => {
|
||||||
|
if (!clientConnected) {
|
||||||
|
logger.log('warn', `No client connected to browser ${id} within timeout, proceeding with dummy socket`);
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
namespace.on('error', (error: any) => {
|
||||||
|
logger.log('error', `Socket namespace error for browser ${id}: ${error.message}`);
|
||||||
|
clearTimeout(connectionTimeout);
|
||||||
|
browserPool.failBrowserSlot(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
const socket = await waitForConnection;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let browserSession: RemoteBrowser;
|
||||||
|
|
||||||
|
if (socket) {
|
||||||
|
logger.log('info', `Using real socket for browser ${id}`);
|
||||||
|
browserSession = new RemoteBrowser(socket, userId, id);
|
||||||
|
} else {
|
||||||
|
logger.log('info', `Using dummy socket for browser ${id}`);
|
||||||
|
const dummySocket = {
|
||||||
|
emit: (event: string, data?: any) => {
|
||||||
|
logger.log('debug', `Browser ${id} dummy socket emitted ${event}:`, data);
|
||||||
|
},
|
||||||
|
on: () => {},
|
||||||
|
id: `dummy-${id}`,
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
browserSession = new RemoteBrowser(dummySocket, userId, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
await browserSession.initialize(userId);
|
||||||
|
|
||||||
|
const upgraded = browserPool.upgradeBrowserSlot(id, browserSession);
|
||||||
|
if (!upgraded) {
|
||||||
|
throw new Error('Failed to upgrade reserved browser slot');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket) {
|
||||||
|
socket.emit('ready-for-run');
|
||||||
|
} else {
|
||||||
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
logger.log('info', `Starting execution for browser ${id} with dummy socket`);
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.log('error', `Error executing run for browser ${id}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log('info', `Browser ${id} successfully initialized for run with ${socket ? 'real' : 'dummy'} socket`);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.log('error', `Error initializing browser ${id}: ${error.message}`);
|
||||||
|
browserPool.failBrowserSlot(id);
|
||||||
|
if (socket) {
|
||||||
|
socket.emit('error', { message: error.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.log('error', `Error setting up browser ${id}: ${error.message}`);
|
||||||
|
browserPool.failBrowserSlot(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user