pomeloes-robot
v2.0.1
Published
A fully modernized pomelo-robot, upgraded with ES6+ and latest dependencies. Now supports standalone mode.
Readme
pomeloes-robot
A fully modernized pomelo-robot, upgraded with ES6+ and the latest dependencies. This tool is designed for benchmarking socket.io servers with robust support for distributed execution and custom scripts.
It executes developer-defined JavaScript in a sandboxed environment, performs statistical analysis (including response time and QPS), and reports data to a web-based dashboard with graphical displays.
Key Features & Fixes
This version introduces a comprehensive modernization and stabilization of the original pomelo-robot:
- Standalone Mode: A new
runStandalone()method allows for rapid development and debugging of a single robot script, bypassing the master/client architecture. - Robust Sandboxing: The
vmsandbox forclientmode has been completely overhauled. It now correctly handlesmodule.exports,__filename,__dirname, and context-awarerequire()calls, making the script execution environment behave like standard Node.js. - Enhanced Debugging: A new
debug: trueoption in the master configuration prints the exactcwdandenvused to spawn client processes, making environment issues transparent. - Flexible Configuration: The new
spawnOptionsconfig allows developers to explicitly set thecwdandenvfor client sub-processes, ensuring consistent behavior. - Native Addon Fix: Permanently resolved crashes related to optional native addons (
bufferutil,utf-8-validate) inwsby disabling them globally via environment variables. - Modern Codebase: The entire library has been refactored to ES6+ syntax (
class,async/await, etc.) and its dependencies (socket.iov4) have been brought up to date. - Logging & Stability: Fixed numerous bugs, including silent swallowing of script errors, unsafe file operations, and broken I/O redirection for logs.
Installation
npm install pomeloes-robotUsage
A typical startup script (app.js) for managing the robot:
const { Robot } = require('pomeloes-robot');
const path = require('path');
// 1. Load your project-specific configuration
// It should define master host/port, client IPs, and the script to run.
const config = require('./config/development.json');
// 2. Instantiate the Robot with the full configuration
const robot = new Robot(config);
// 3. Determine the run mode (master, client, or standalone)
const mode = process.argv[2] || 'master';
if (!['master', 'client', 'standalone'].includes(mode)) {
throw new Error('Mode must be master, client, or standalone');
}
// 4. Construct the absolute path to your robot script
const scriptPath = path.join(process.cwd(), config.script);
// 5. Run in the selected mode
switch (mode) {
case 'master':
// The master needs the path to this startup file to spawn clients
robot.runMaster(__filename);
break;
case 'client':
robot.runAgent(scriptPath);
break;
case 'standalone':
robot.runStandalone(scriptPath);
break;
}Writing Robot Scripts
To ensure your script works correctly in both standalone and master/client modes, follow this pattern:
// my-robot-script.js
// This script should export a single function.
module.exports = async function(app) {
// Use the actor object provided by the framework to emit events.
const actor = app.get('actor');
console.log(`[Actor ${actor.id}] Starting script...`);
try {
// Your script is responsible for creating and managing the pomelo client.
const pomelo = require('pomelo-jsclient-websocket');
// Perform connection, requests, etc.
await new Promise((resolve, reject) => {
pomelo.init({ host: '127.0.0.1', port: 3010 }, (err) => {
if (err) return reject(err);
console.log(`[Actor ${actor.id}] Connected to server.`);
resolve();
});
});
// ... your test logic here ...
console.log(`[Actor ${actor.id}] Script finished successfully.`);
pomelo.disconnect();
} catch (e) {
console.error(`[Actor ${actor.id}] An error occurred:`, e);
} finally {
// IMPORTANT: Signal that the script is done.
// In client mode, this tells the master the run is complete.
// In standalone mode, this will exit the process.
actor.emit('done');
}
};Advanced Configuration
You can pass a configuration object to the Robot constructor to customize its behavior.
const config = {
master: { host: '127.0.0.1', port: 8089, webport: 8090 },
clients: ['127.0.0.1'],
script: 'app/scripts/my-robot-script.js',
debug: true, // Enable debug mode
spawnOptions: {
cwd: '/path/to/project/root',
env: { "NODE_CONFIG_DIR": "./config" }
}
};debug(boolean): Iftrue, the master process will print the full options object (cwd,env) used to spawn client sub-processes.spawnOptions(object): Allows you to explicitly control the execution environment of client sub-processes.
API Reference
robot.runMaster(mainFile)
Runs the master server and an HTTP web console. The master will then wait for a "ready" signal from the web console to spawn the client agents using child_process.spawn.
mainFile(string): The absolute path to your main startup script (e.g.,__filename). This is required by the master to construct the command for spawning new client processes.
robot.runAgent(scriptPath)
Runs the robot in client agent mode. The agent connects to the master server, waits for instructions, and then executes the specified script in a sandboxed vm context.
scriptPath(string): The absolute path to the robot script to execute.
robot.runStandalone(scriptPath)
Runs a single robot script in the current process, bypassing the master/client architecture. Ideal for rapid development and debugging.
scriptPath(string): The absolute path to the robot script. The script is loaded viarequire()and its exported function is invoked.
