A service to manage monitor and spawn subprocess
Project description
Subprocess Monitor
A robust Python service for managing, monitoring, and spawning subprocesses with advanced lifecycle management features. Provides both a Python API and CLI interface for subprocess operations using async/await patterns.
Table of Contents
- Why Subprocess Monitor?
- Key Features
- Installation
- Quick Start
- Use Cases vs Built-in subprocess
- API Reference
- CLI Usage
- Architecture
- Development
Why Subprocess Monitor?
While Python's built-in subprocess module is excellent for basic process management, subprocess-monitor provides enterprise-grade features for complex subprocess orchestration:
Problems with Built-in subprocess
- No centralized management: Each subprocess is isolated
- Manual lifecycle tracking: You must track PIDs and process states yourself
- No real-time monitoring: Limited ability to stream output in real-time
- Complex async patterns: Difficult to integrate with async/await workflows
- No process persistence: Processes die with parent termination
- Limited observability: No built-in logging or monitoring
Subprocess Monitor Solutions
- Centralized service: Single point of control for all subprocesses
- Automatic lifecycle management: Built-in process tracking and cleanup
- Real-time streaming: WebSocket-based output streaming
- Async-first design: Native async/await support throughout
- Process persistence: Processes can outlive parent applications
- Rich observability: Comprehensive logging and monitoring
- Cross-platform compatibility: Works on Windows, Linux, and macOS
- REST API: HTTP endpoints for remote process management
- Type safety: Full TypeScript-style typing with runtime validation
Key Features
๐ฏ Centralized Process Management
- Single service manages multiple subprocesses
- Automatic PID tracking and process ownership
- Built-in process cleanup and resource management
๐ Real-time Monitoring
- WebSocket subscriptions for live output streaming
- Process state change notifications
- Resource usage monitoring
โก Async/Await Native
- Built on aiohttp for high-performance async operations
- Non-blocking subprocess operations
- Concurrent process management
๐ก๏ธ Enterprise Security
- Runtime type validation prevents injection attacks
- Secure port binding prevents race conditions
- Process isolation and sandboxing
๐ Cross-Platform
- Windows, Linux, and macOS support
- Platform-specific optimizations
- Unified API across all platforms
๐ Multiple Interfaces
- Python API for programmatic access
- CLI for terminal operations
- REST API for remote management
- WebSocket API for real-time updates
Installation
# Using pip
pip install subprocess-monitor
# Using uv (recommended)
uv add subprocess-monitor
# From source
git clone https://github.com/JulianKimmig/subprocess_monitor
cd subprocess-monitor
uv sync
Quick Start
Python API
import asyncio
from subprocess_monitor import SubprocessMonitor
async def main():
# For server-side usage
monitor = SubprocessMonitor(host="localhost", port=8080)
server_task = asyncio.create_task(monitor.run())
# For client-side usage (more common)
from subprocess_monitor.helper import send_spawn_request, get_status
# Start a subprocess via API
response = await send_spawn_request(
"python", ["-c", "print('Hello World')"],
env={"MY_VAR": "value"}, host="localhost", port=8080
)
pid = response["pid"]
print(f"Started process {pid}")
# Get status
processes = await get_status(host="localhost", port=8080)
print(f"Active processes: {processes}")
asyncio.run(main())
CLI Usage
# Start the monitor service
subprocess-monitor start --port 8080
# Spawn a process
subprocess-monitor spawn python -c "print('Hello World')"
# Check status
subprocess-monitor status
# Stop a process
subprocess-monitor stop <pid>
# Subscribe to process output
subprocess-monitor subscribe <pid>
Use Cases vs Built-in subprocess
When to Use Built-in subprocess
โ Simple one-off commands
import subprocess
result = subprocess.run(["ls", "-la"], capture_output=True, text=True)
print(result.stdout)
โ Synchronous workflows
with subprocess.Popen(["python", "script.py"]) as proc:
proc.wait()
โ Basic process communication
proc = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = proc.communicate(input="print('hello')")
When to Use Subprocess Monitor
โ Long-running process orchestration
# Built-in subprocess - complex manual management
processes = []
for i in range(10):
proc = subprocess.Popen(["worker.py", f"--id={i}"])
processes.append(proc)
# Subprocess Monitor - simple centralized management
monitor = SubprocessMonitor()
for i in range(10):
await monitor.start_subprocess({"cmd": "python", "args": ["worker.py", f"--id={i}"]})
โ Real-time output monitoring
# Built-in subprocess - polling required
proc = subprocess.Popen(["tail", "-f", "log.txt"], stdout=subprocess.PIPE)
for line in iter(proc.stdout.readline, b''):
print(line.decode())
# Subprocess Monitor - WebSocket streaming
async with websockets.connect(f"ws://localhost:8080/subscribe?pid={pid}") as ws:
async for message in ws:
data = json.loads(message)
print(f"{data['stream']}: {data['data']}")
โ Async/await workflows
# Built-in subprocess - complex async integration
async def run_process():
proc = await asyncio.create_subprocess_exec("python", "script.py")
await proc.wait()
# Subprocess Monitor - native async support
async def run_process():
pid = await monitor.start_subprocess({"cmd": "python", "args": ["script.py"]})
# Process runs in background - monitor via subscribe_output endpoint
โ Process lifecycle management
# Built-in subprocess - manual cleanup
import atexit
import signal
processes = []
def cleanup():
for proc in processes:
proc.terminate()
proc.wait()
atexit.register(cleanup)
signal.signal(signal.SIGTERM, lambda s, f: cleanup())
# Subprocess Monitor - automatic cleanup
monitor = SubprocessMonitor() # Handles all cleanup automatically
โ Remote process management
# Built-in subprocess - local only
subprocess.run(["python", "script.py"])
# Subprocess Monitor - remote management via REST API
import aiohttp
async with aiohttp.ClientSession() as session:
async with session.post("http://remote:8080/spawn", json={
"cmd": "python", "args": ["script.py"]
}) as resp:
result = await resp.json()
print(f"Started remote process {result['pid']}")
โ Multi-service coordination
# Start multiple interdependent services
services = [
{"cmd": "redis-server", "args": []},
{"cmd": "python", "args": ["api_server.py"]},
{"cmd": "python", "args": ["worker.py"]},
{"cmd": "nginx", "args": ["-c", "nginx.conf"]}
]
monitor = SubprocessMonitor()
pids = []
for service in services:
pid = await monitor.start_subprocess(service)
pids.append(pid)
await asyncio.sleep(1) # Staggered startup
# Monitor all services via WebSocket (client-side implementation needed)
# WebSocket endpoint: ws://localhost:8080/subscribe?pid={pid}
API Reference
SubprocessMonitor Class
Constructor
SubprocessMonitor(
host: str = "localhost",
port: Optional[int] = None,
check_interval: float = 2.0,
logger: Optional[logging.Logger] = None
)
Methods
async start_subprocess(request: SpawnProcessRequest) -> int
- Spawns a new subprocess
- Returns the process PID
- Automatically tracks process lifecycle
async stop_subprocess(pid: int) -> bool
- Terminates a subprocess by PID
- Returns True if successful
- Handles cleanup automatically
Note: The SubprocessMonitor class provides internal process management. For client access, use the helper functions or REST API endpoints:
- GET /: Returns list of active process PIDs
- POST /spawn: Spawn a new subprocess
- POST /stop: Stop a subprocess by PID
- WebSocket /subscribe?pid={pid}: Subscribe to real-time process output
Helper Functions
async send_spawn_request(cmd: str, args: List[str], env: Dict[str, str] = None, host: str = None, port: int = None) -> SpawnRequestResponse
async send_stop_request(pid: int, host: str = None, port: int = None) -> StopRequestResponse
async get_status(host: str = None, port: int = None) -> List[int]
CLI Usage
Starting the Service
# Start with default settings
subprocess-monitor start
# Start with custom port
subprocess-monitor start --port 8080
# Start with custom host and port
subprocess-monitor start --host 0.0.0.0 --port 8080
Process Management
# Spawn a simple command
subprocess-monitor spawn echo "Hello World"
# Spawn with arguments
subprocess-monitor spawn python script.py --arg1 value1
# Spawn with environment variables
subprocess-monitor spawn --env VAR1=value1 --env VAR2=value2 python script.py
# Check active processes
subprocess-monitor status
# Stop a process
subprocess-monitor stop 12345
# Subscribe to process output
subprocess-monitor subscribe 12345
Environment Variables
SUBPROCESS_MONITOR_HOST: Default host (default: localhost)SUBPROCESS_MONITOR_PORT: Default port (default: 5000)SUBPROCESS_MONITOR_PID: Monitor service PID (auto-set)
Architecture
Core Components
subprocess_monitor/
โโโ __init__.py # Package exports
โโโ __main__.py # CLI entry point
โโโ subprocess_monitor.py # Core service logic
โโโ helper.py # Client helper functions
โโโ types.py # TypedDict definitions
โโโ defaults.py # Configuration constants
โโโ validation.py # Runtime type validation
Key Design Patterns
Async/Await First: Built on asyncio and aiohttp for high-performance async operations
Type Safety: Full typing with runtime validation using TypedDict and custom validators
Resource Management: Automatic cleanup of processes, sockets, and WebSocket connections
Cross-Platform: Unified API with platform-specific optimizations
Security: Input validation, secure port binding, and process isolation
Service Architecture
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ CLI Client โ โ Python API โ โ HTTP Client โ
โโโโโโโโโโโฌโโโโโโโโ โโโโโโโโโโโฌโโโโโโโโโ โโโโโโโโโโโฌโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโโ
โ Subprocess Monitor โ
โ (aiohttp server) โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโผโโโโโโโโโ โโโโโโโโโโโผโโโโโโโโโ โโโโโโโโโโโผโโโโโโโโโ
โ REST Endpoints โ โ WebSocket Stream โ โ Process Manager โ
โ /spawn โ โ /subscribe โ โ - Lifecycle โ
โ /stop โ โ Real-time I/O โ โ - Monitoring โ
โ /status โ โ JSON messages โ โ - Cleanup โ
โโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
Development
Setup
# Clone and setup
git clone https://github.com/JulianKimmig/subprocess_monitor
cd subprocess-monitor
uv sync
# Install pre-commit hooks
uv run pre-commit install
Testing
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=subprocess_monitor
# Run specific test
uv run pytest tests/test_sm.py::TestHelperFunctions::test_send_spawn_request
Code Quality
# Format code
uv run ruff format .
# Lint code
uv run ruff check . --fix
# Type checking
uv run flake8
# Security scanning
uv run vulture subprocess_monitor
# Run all checks
uv run pre-commit run --all-files
Project Structure
- Type Safety: Uses TypedDict for API contracts with runtime validation
- Async Patterns: Built on asyncio for non-blocking operations
- Testing: Comprehensive test suite with IsolatedAsyncioTestCase
- Security: Input validation and secure resource management
- Cross-Platform: Works on Windows, Linux, and macOS
License
MIT License - see LICENSE file for details.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Run the full test suite
- Submit a pull request
Support
- ๐ Bug Reports: GitHub Issues
- ๐ฌ Discussions: GitHub Discussions
- ๐ Documentation: Wiki
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file subprocess_monitor-0.4.0.tar.gz.
File metadata
- Download URL: subprocess_monitor-0.4.0.tar.gz
- Upload date:
- Size: 122.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcb40d351d8ee501e7291064cc29e5459e406b51bc7739803b1a1b430bb20aeb
|
|
| MD5 |
fcf6759351def265eebf0bb527333694
|
|
| BLAKE2b-256 |
945a8b70bd3d6340c8c39e05bc68b28c22beae2aa1b908a16001cd71873f3c0b
|
Provenance
The following attestation bundles were made for subprocess_monitor-0.4.0.tar.gz:
Publisher:
version_publish_main.yml on JulianKimmig/subprocess_monitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
subprocess_monitor-0.4.0.tar.gz -
Subject digest:
bcb40d351d8ee501e7291064cc29e5459e406b51bc7739803b1a1b430bb20aeb - Sigstore transparency entry: 776206637
- Sigstore integration time:
-
Permalink:
JulianKimmig/subprocess_monitor@cffd7fe12fe90a65d21ed3909ff43a5b1e9cab57 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/JulianKimmig
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
version_publish_main.yml@cffd7fe12fe90a65d21ed3909ff43a5b1e9cab57 -
Trigger Event:
push
-
Statement type:
File details
Details for the file subprocess_monitor-0.4.0-py3-none-any.whl.
File metadata
- Download URL: subprocess_monitor-0.4.0-py3-none-any.whl
- Upload date:
- Size: 19.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d931b0ecb5bd7ba33be62e9cd24c785a3b6ffe332e0addfe3b5acd689a6847b3
|
|
| MD5 |
99ac738ae05e52ce82351e68ae49b5d9
|
|
| BLAKE2b-256 |
caf0e78794052f46181bd881455e25e726dcb3494502dc1b15d9883764c02b41
|
Provenance
The following attestation bundles were made for subprocess_monitor-0.4.0-py3-none-any.whl:
Publisher:
version_publish_main.yml on JulianKimmig/subprocess_monitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
subprocess_monitor-0.4.0-py3-none-any.whl -
Subject digest:
d931b0ecb5bd7ba33be62e9cd24c785a3b6ffe332e0addfe3b5acd689a6847b3 - Sigstore transparency entry: 776206639
- Sigstore integration time:
-
Permalink:
JulianKimmig/subprocess_monitor@cffd7fe12fe90a65d21ed3909ff43a5b1e9cab57 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/JulianKimmig
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
version_publish_main.yml@cffd7fe12fe90a65d21ed3909ff43a5b1e9cab57 -
Trigger Event:
push
-
Statement type: