feat: optimize remote browser perf

This commit is contained in:
Rohit
2025-06-12 14:30:43 +05:30
parent 7c5f88cf0e
commit 7633c4730d

View File

@@ -25,6 +25,13 @@ const MEMORY_CONFIG = {
heapUsageThreshold: 0.7 // 70% (reduced threshold to react earlier) heapUsageThreshold: 0.7 // 70% (reduced threshold to react earlier)
}; };
const DEFAULT_VIEWPORT = {
width: 1280,
height: 720,
deviceScaleFactor: 1,
mobile: false
};
const SCREENCAST_CONFIG: { const SCREENCAST_CONFIG: {
format: "jpeg" | "png"; format: "jpeg" | "png";
maxWidth: number; maxWidth: number;
@@ -32,13 +39,17 @@ const SCREENCAST_CONFIG: {
targetFPS: number; targetFPS: number;
compressionQuality: number; compressionQuality: number;
maxQueueSize: number; maxQueueSize: number;
skipFrameThreshold: number,
enableAdaptiveQuality: boolean,
} = { } = {
format: 'png', format: 'jpeg',
maxWidth: 1280, maxWidth: DEFAULT_VIEWPORT.width,
maxHeight: 720, maxHeight: DEFAULT_VIEWPORT.height,
targetFPS: 15, targetFPS: 30,
compressionQuality: 0.95, compressionQuality: 0.8,
maxQueueSize: 1 maxQueueSize: 2,
skipFrameThreshold: 100,
enableAdaptiveQuality: true,
}; };
/** /**
@@ -125,6 +136,18 @@ export class RemoteBrowser {
this.generator = new WorkflowGenerator(socket, poolId); this.generator = new WorkflowGenerator(socket, poolId);
} }
private cleanupMemory(): void {
if (this.screenshotQueue.length > 10) {
this.screenshotQueue = this.screenshotQueue.slice(-3); // Keep only last 3
}
}
private setupMemoryCleanup(): void {
setInterval(() => {
this.cleanupMemory();
}, 30000); // Every 30 seconds
}
private initializeMemoryManagement(): void { private initializeMemoryManagement(): void {
setInterval(() => { setInterval(() => {
const memoryUsage = process.memoryUsage(); const memoryUsage = process.memoryUsage();
@@ -412,6 +435,7 @@ export class RemoteBrowser {
} }
} }
this.setupMemoryCleanup();
// this.initializeMemoryManagement(); // this.initializeMemoryManagement();
}; };
@@ -1399,7 +1423,7 @@ export class RemoteBrowser {
*/ */
private emitScreenshot = async (payload: Buffer, viewportSize?: { width: number, height: number }): Promise<void> => { private emitScreenshot = async (payload: Buffer, viewportSize?: { width: number, height: number }): Promise<void> => {
if (this.screenshotQueue.length > SCREENCAST_CONFIG.maxQueueSize) { if (this.screenshotQueue.length > SCREENCAST_CONFIG.maxQueueSize) {
this.screenshotQueue = this.screenshotQueue.slice(-SCREENCAST_CONFIG.maxQueueSize); this.screenshotQueue = this.screenshotQueue.slice(-1);
} }
if (this.isProcessingScreenshot) { if (this.isProcessingScreenshot) {
@@ -1414,7 +1438,7 @@ export class RemoteBrowser {
try { try {
const optimizationPromise = this.optimizeScreenshot(payload); const optimizationPromise = this.optimizeScreenshot(payload);
const timeoutPromise = new Promise<Buffer>((resolve) => { const timeoutPromise = new Promise<Buffer>((resolve) => {
setTimeout(() => resolve(payload), 150); setTimeout(() => resolve(payload), 100);
}); });
const optimizedScreenshot = await Promise.race([optimizationPromise, timeoutPromise]); const optimizedScreenshot = await Promise.race([optimizationPromise, timeoutPromise]);
@@ -1423,10 +1447,12 @@ export class RemoteBrowser {
payload = null as any; payload = null as any;
this.socket.emit('screencast', { setImmediate(async () => {
this.socket.emit('screencast', {
image: dataWithMimeType, image: dataWithMimeType,
userId: this.userId, userId: this.userId,
viewport: viewportSize || await this.currentPage?.viewportSize() || null viewport: viewportSize || await this.currentPage?.viewportSize() || null
});
}); });
} catch (error) { } catch (error) {
logger.error('Screenshot emission failed:', error); logger.error('Screenshot emission failed:', error);
@@ -1434,24 +1460,27 @@ export class RemoteBrowser {
const base64Data = payload.toString('base64'); const base64Data = payload.toString('base64');
const dataWithMimeType = `data:image/png;base64,${base64Data}`; const dataWithMimeType = `data:image/png;base64,${base64Data}`;
this.socket.emit('screencast', { setImmediate(async () => {
image: dataWithMimeType, this.socket.emit('screencast', {
userId: this.userId, image: dataWithMimeType,
viewport: viewportSize || await this.currentPage?.viewportSize() || null userId: this.userId,
viewport: viewportSize || await this.currentPage?.viewportSize() || null
});
}); });
} catch (e) { } catch (e) {
logger.error('Fallback screenshot emission also failed:', e); logger.error('Fallback screenshot emission also failed:', e);
} }
} finally { } finally {
this.isProcessingScreenshot = false; this.isProcessingScreenshot = false;
if (this.screenshotQueue.length > 0) { if (this.screenshotQueue.length > 0) {
const nextScreenshot = this.screenshotQueue.shift(); const nextScreenshot = this.screenshotQueue.shift();
if (nextScreenshot) { if (nextScreenshot) {
setTimeout(() => { const delay = this.screenshotQueue.length > 0 ? 16 : 33;
this.emitScreenshot(nextScreenshot); setTimeout(() => {
}, 1000 / SCREENCAST_CONFIG.targetFPS); this.emitScreenshot(nextScreenshot);
} }, delay);
}
} }
} }
}; };