# parallel-runner > Run multiple commands or tests in parallel with proper signal handling and exit code propagation. - Author: a.mor - Repository: alimrb/suruf-platform-repo - Version: 20260208142121 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-08 - Source: https://github.com/alimrb/suruf-platform-repo - Web: https://mule.run/skillshub/@@alimrb/suruf-platform-repo~parallel-runner:20260208142121 --- --- name: parallel-runner description: "Run multiple commands or tests in parallel with proper signal handling and exit code propagation." --- # Parallel Runner Skill Execute multiple commands, tests, or scripts in parallel while properly handling signals and exit codes. ## Basic Parallel Execution (Bash) ```bash #!/bin/bash # Run commands in parallel and wait for all # Method 1: Background jobs npm run lint & npm run test & npm run build & wait # Wait for all background jobs # Method 2: With exit code tracking pids=() npm run lint & pids+=($!) npm run test & pids+=($!) npm run build & pids+=($!) # Wait and capture exit codes exit_code=0 for pid in "${pids[@]}"; do wait $pid || exit_code=$? done exit $exit_code ``` ## Node.js Parallel Runner ```javascript // parallel-runner.mjs import { spawn } from "node:child_process"; import os from "node:os"; const children = new Set(); const maxWorkers = Math.max(4, Math.min(16, os.cpus().length)); const run = (command, args = []) => new Promise((resolve) => { const child = spawn(command, args, { stdio: "inherit", shell: process.platform === "win32", }); children.add(child); child.on("exit", (code, signal) => { children.delete(child); resolve(code ?? (signal ? 1 : 0)); }); }); // Graceful shutdown on signals const shutdown = (signal) => { for (const child of children) { child.kill(signal); } }; process.on("SIGINT", () => shutdown("SIGINT")); process.on("SIGTERM", () => shutdown("SIGTERM")); // Define tasks const tasks = [ { name: "lint", cmd: "npm", args: ["run", "lint"] }, { name: "test", cmd: "npm", args: ["run", "test"] }, { name: "build", cmd: "npm", args: ["run", "build"] }, ]; // Run in parallel console.log(`Running ${tasks.length} tasks in parallel (max ${maxWorkers} workers)`); const results = await Promise.all( tasks.map(async (task) => { console.log(`Starting: ${task.name}`); const code = await run(task.cmd, task.args); console.log(`Finished: ${task.name} (exit code: ${code})`); return { name: task.name, code }; }) ); // Report results const failed = results.filter((r) => r.code !== 0); if (failed.length > 0) { console.error("Failed tasks:", failed.map((r) => r.name).join(", ")); process.exit(1); } console.log("All tasks completed successfully"); process.exit(0); ``` ## Python Parallel Runner ```python # parallel_runner.py import subprocess import concurrent.futures import sys import signal tasks = [ ("lint", ["npm", "run", "lint"]), ("test", ["pytest", "-v"]), ("build", ["npm", "run", "build"]), ] def run_task(name, cmd): """Run a single task and return result.""" print(f"Starting: {name}") result = subprocess.run(cmd, capture_output=False) print(f"Finished: {name} (exit code: {result.returncode})") return (name, result.returncode) def main(): # Handle Ctrl+C gracefully signal.signal(signal.SIGINT, lambda s, f: sys.exit(130)) with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor: futures = { executor.submit(run_task, name, cmd): name for name, cmd in tasks } results = [] for future in concurrent.futures.as_completed(futures): results.append(future.result()) # Check for failures failed = [name for name, code in results if code != 0] if failed: print(f"Failed: {', '.join(failed)}") sys.exit(1) print("All tasks completed successfully") if __name__ == "__main__": main() ``` ## GNU Parallel (if installed) ```bash # Run commands from a file in parallel cat < tasks.txt npm run lint npm run test:unit npm run test:integration EOF parallel --jobs 4 < tasks.txt # Or inline parallel ::: "npm run lint" "npm run test" "npm run build" # With progress bar parallel --progress --jobs 4 ::: "sleep 1" "sleep 2" "sleep 3" ``` ## Makefile Parallel Targets ```makefile # Run targets in parallel: make -j4 all .PHONY: all lint test build all: lint test build lint: npm run lint test: npm run test build: npm run build ``` ## Tips - Use `--jobs` or `-j` flag with make for parallel execution - Set `maxWorkers` based on CPU cores to avoid overloading - Always handle SIGINT/SIGTERM for clean shutdown - Capture exit codes to fail fast on errors - Use `stdio: "inherit"` to preserve colored output