Heuristic:MarketSquare Robotframework browser Shared Node Process For Parallel
| Knowledge Sources | |
|---|---|
| Domains | Optimization, Testing |
| Last Updated | 2026-02-12 04:00 GMT |
Overview
Performance optimization that spawns a single shared Playwright Node.js process for parallel test execution with Pabot, instead of one process per worker.
Description
When running tests in parallel with Robot Framework Pabot, each worker normally spawns its own Playwright Node.js process. This is wasteful because each process loads the same Playwright binaries and consumes significant memory. The `spawn_node_process` utility function creates a single shared Node.js process and passes its port number via the `ROBOT_FRAMEWORK_BROWSER_NODE_PORT` environment variable. All Pabot workers then connect to this shared process instead of starting their own.
Usage
Use this pattern when running Browser library tests in parallel with Pabot or when optimizing CI execution time and memory usage. It is especially beneficial in resource-constrained environments like Docker containers or CI runners with limited memory.
The Insight (Rule of Thumb)
- Action: Before starting Pabot, spawn a shared Node.js process using `spawn_node_process()` and set `ROBOT_FRAMEWORK_BROWSER_NODE_PORT` to the returned port.
- Value: Reduces memory usage proportionally to the number of Pabot workers (e.g., 4 workers = ~75% reduction in Node.js memory).
- Trade-off: All workers share a single Node.js process, which becomes a single point of failure. If the shared process crashes, all workers fail.
Reasoning
The Playwright Node.js process loads browser binaries and maintains gRPC connections. Each instance consumes 100-200MB of memory. With 4+ Pabot workers each spawning their own process, memory usage becomes significant. The shared process approach was designed into the library from the start, with the `ROBOT_FRAMEWORK_BROWSER_NODE_PORT` environment variable serving as the coordination mechanism.
Code Evidence
From `Browser/utils/misc.py:47-72`:
def spawn_node_process(output_dir: Path) -> tuple[subprocess.Popen, str]:
"""
Spawn an rfbrowser node process, that can be shared between library instances.
Usage example:
rc = 1
background_process, port = spawn_node_process(ATEST_OUTPUT / "playwright-log.txt")
try:
os.environ["ROBOT_FRAMEWORK_BROWSER_NODE_PORT"] = port
rc = _run_pabot(args)
finally:
background_process.kill()
"""
Port detection in `Browser/playwright.py:136-150`:
env_node_port = os.environ.get("ROBOT_FRAMEWORK_BROWSER_NODE_PORT")
existing_port = self.port or env_node_port
if existing_port is not None:
self.port = existing_port
if self.host is None:
self.host = "127.0.0.1"