feat: optimize remote browser perf
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user