292 lines
9.9 KiB
Markdown
292 lines
9.9 KiB
Markdown
# OpenCode Process Manager
|
||
|
||
## Overview
|
||
|
||
This document explains the OpenCode Process Manager implementation, which optimizes resource usage by managing OpenCode sessions through a singleton instance manager.
|
||
|
||
## Problem Statement
|
||
|
||
Previously, the application spawned a **new OpenCode process for every message** sent by users. This meant:
|
||
- Multiple concurrent sessions resulted in dozens of separate OpenCode processes
|
||
- High memory and CPU overhead from process spawning
|
||
- No process reuse or pooling
|
||
- Inefficient resource utilization
|
||
|
||
## Solution
|
||
|
||
The `OpencodeProcessManager` class provides a singleton manager that:
|
||
|
||
1. **Tracks all OpenCode sessions** in a centralized location
|
||
2. **Monitors process execution** with detailed logging
|
||
3. **Prepares for future optimization** when OpenCode supports server/daemon mode
|
||
4. **Falls back gracefully** to per-message spawning when server mode is unavailable
|
||
|
||
## Current Implementation
|
||
|
||
### Architecture
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ Multiple User Sessions │
|
||
│ (Session A, B, C, D...) │
|
||
└───────────┬─────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ OpencodeProcessManager (Singleton) │
|
||
│ - Tracks all sessions │
|
||
│ - Monitors execution │
|
||
│ - Manages process lifecycle │
|
||
└───────────┬─────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ OpenCode CLI Execution │
|
||
│ (Currently: per-message processes) │
|
||
│ (Future: single daemon instance) │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
### Key Features
|
||
|
||
1. **Singleton Pattern**: Only one `OpencodeProcessManager` instance exists across the entire application
|
||
2. **Session Tracking**: Maps session IDs to their workspace directories
|
||
3. **Process Monitoring**: Logs execution time, active processes, and resource usage
|
||
4. **Graceful Degradation**: Falls back to per-message spawning if server mode unavailable
|
||
5. **Lifecycle Management**: Properly initialized on startup and cleaned up on shutdown
|
||
|
||
### Code Locations
|
||
|
||
- **Manager Class**: Lines ~575-836 in [server.js](chat/server.js)
|
||
- **Singleton Instance**: Line ~838 in [server.js](chat/server.js)
|
||
- **Integration**: Line ~6165 in [server.js](chat/server.js) (sendToOpencode function)
|
||
- **Initialization**: Lines ~11239-11246 in [server.js](chat/server.js) (bootstrap function)
|
||
- **Shutdown**: Line ~981 in [server.js](chat/server.js) (gracefulShutdown function)
|
||
- **Status Endpoint**: Lines ~9832-9867 in [server.js](chat/server.js)
|
||
|
||
## Current Behavior
|
||
|
||
### What Happens Now
|
||
|
||
Since OpenCode doesn't currently support a persistent server/daemon mode, the manager:
|
||
|
||
1. **Tracks each execution** with detailed logging
|
||
2. **Reports statistics** via the `/api/opencode/status` endpoint
|
||
3. **Routes through `executeStandalone`** which spawns per-message processes
|
||
4. **Logs process lifecycle** (start, duration, completion)
|
||
|
||
This provides:
|
||
- ✅ Better visibility into OpenCode usage
|
||
- ✅ Centralized execution management
|
||
- ✅ Foundation for future optimization
|
||
- ⚠️ Still spawns separate processes per message (but tracked)
|
||
|
||
## Future Optimization
|
||
|
||
### When OpenCode Adds Server Mode
|
||
|
||
If/when OpenCode supports a persistent server/daemon mode (e.g., `opencode serve` or `opencode daemon`):
|
||
|
||
1. **Update `getServerModeArgs()`** to return the correct command arguments
|
||
2. **The manager will automatically**:
|
||
- Start a single OpenCode process on server startup
|
||
- Route all sessions through this single instance
|
||
- Maintain persistent connections
|
||
- Dramatically reduce resource overhead
|
||
|
||
### Expected Benefits (Future)
|
||
|
||
When server mode is available:
|
||
- **90%+ reduction** in process spawning overhead
|
||
- **Faster response times** (no process startup delay)
|
||
- **Lower memory usage** (one process vs. many)
|
||
- **Better session continuity** (persistent state)
|
||
|
||
## Monitoring
|
||
|
||
### Status Endpoint
|
||
|
||
Check OpenCode manager status:
|
||
```bash
|
||
curl http://localhost:3000/api/opencode/status
|
||
```
|
||
|
||
Response includes:
|
||
```json
|
||
{
|
||
"available": true,
|
||
"version": "...",
|
||
"runningProcesses": 3,
|
||
"activeStreams": 2,
|
||
"processManager": {
|
||
"isRunning": false,
|
||
"isReady": true,
|
||
"pendingRequests": 0,
|
||
"activeSessions": 5,
|
||
"lastActivity": 1234567890,
|
||
"idleTime": 1234,
|
||
"mode": "per-session",
|
||
"description": "Each message spawns separate OpenCode process"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Logging
|
||
|
||
The manager logs:
|
||
- Process execution start/end
|
||
- Duration of each command
|
||
- Active process count
|
||
- Session workspace mapping
|
||
- Errors and failures
|
||
|
||
Look for log entries with:
|
||
- `"OpenCode process manager..."`
|
||
- `"Executing OpenCode command (standalone)"`
|
||
- `"OpenCode command completed"`
|
||
|
||
## Implementation Details
|
||
|
||
### OpencodeProcessManager Class
|
||
|
||
#### Properties
|
||
- `process`: Reference to the persistent OpenCode process (when in server mode)
|
||
- `isReady`: Boolean indicating if the manager is ready to accept requests
|
||
- `pendingRequests`: Map of in-flight requests awaiting responses
|
||
- `sessionWorkspaces`: Map of session IDs to their workspace directories
|
||
- `lastActivity`: Timestamp of last activity (for idle detection)
|
||
- `heartbeatInterval`: Timer for keeping persistent connection alive
|
||
|
||
#### Methods
|
||
|
||
**`start()`**
|
||
- Initializes the manager
|
||
- Attempts to start OpenCode in server mode
|
||
- Falls back to per-session mode if unavailable
|
||
|
||
**`executeInSession(sessionId, workspaceDir, command, args, options)`**
|
||
- Main execution method
|
||
- Routes through persistent process (future) or standalone spawning (current)
|
||
- Tracks session -> workspace mapping
|
||
|
||
**`executeStandalone(workspaceDir, command, args, options)`**
|
||
- Current fallback implementation
|
||
- Spawns individual OpenCode process
|
||
- Logs execution metrics
|
||
|
||
**`stop()`**
|
||
- Gracefully shuts down manager
|
||
- Terminates persistent process if running
|
||
- Cleans up resources
|
||
|
||
**`getStats()`**
|
||
- Returns current manager statistics
|
||
- Used by monitoring endpoint
|
||
|
||
### Integration Points
|
||
|
||
1. **Bootstrap** (startup): Manager initialized after all state is loaded
|
||
2. **sendToOpencode**: Routes all OpenCode executions through manager
|
||
3. **gracefulShutdown**: Stops manager before server shutdown
|
||
4. **Status endpoint**: Exposes manager statistics
|
||
|
||
## Testing
|
||
|
||
### Verify Installation
|
||
|
||
1. Start the server:
|
||
```bash
|
||
node chat/server.js
|
||
```
|
||
|
||
2. Check the logs for:
|
||
```
|
||
Initializing OpenCode process manager...
|
||
OpenCode does not support server mode, will use per-session approach
|
||
OpenCode process manager initialized
|
||
```
|
||
|
||
3. Check status endpoint:
|
||
```bash
|
||
curl http://localhost:3000/api/opencode/status | jq .
|
||
```
|
||
|
||
4. Send a message in a session and observe logs:
|
||
```
|
||
Executing OpenCode command (standalone) { processId: '...', activeProcesses: 1 }
|
||
OpenCode command completed { processId: '...', duration: 1234 }
|
||
```
|
||
|
||
### Multiple Concurrent Sessions
|
||
|
||
1. Open multiple builder sessions in different browser tabs
|
||
2. Send messages in each
|
||
3. Check `/api/opencode/status` to see `runningProcesses` count
|
||
4. Each process should be logged with start/end times
|
||
|
||
## Configuration
|
||
|
||
No configuration required. The manager automatically:
|
||
- Detects if OpenCode supports server mode
|
||
- Falls back to per-session spawning
|
||
- Adapts to available capabilities
|
||
|
||
## Performance Impact
|
||
|
||
### Current (Per-Session Mode)
|
||
- ✅ Better tracking and visibility
|
||
- ✅ Centralized management
|
||
- ✅ Foundation for future optimization
|
||
- ➖ No performance improvement yet (still spawns separate processes)
|
||
|
||
### Future (Server Mode)
|
||
- ✅ 90%+ reduction in process overhead
|
||
- ✅ Faster response times
|
||
- ✅ Lower memory usage
|
||
- ✅ Better resource utilization
|
||
|
||
## Migration Notes
|
||
|
||
This change is **backward compatible**:
|
||
- No changes to session management
|
||
- No changes to API endpoints (except enhanced status response)
|
||
- No changes to client behavior
|
||
- Existing sessions continue to work
|
||
|
||
## Troubleshooting
|
||
|
||
### Manager Not Starting
|
||
Check logs for: `"OpenCode process manager initialization failed"`
|
||
- This is expected if OpenCode doesn't support server mode
|
||
- Manager falls back to per-session spawning automatically
|
||
|
||
### Multiple Processes Still Running
|
||
This is **expected behavior** in current mode:
|
||
- Each message spawns a separate process
|
||
- This will change when OpenCode adds server mode support
|
||
- All processes are now tracked and logged
|
||
|
||
### Status Endpoint Not Responding
|
||
1. Verify server is running
|
||
2. Check that route is registered in `routeInternal()`
|
||
3. Look for initialization errors in logs
|
||
|
||
## Future Enhancements
|
||
|
||
1. **Add Server Mode Support**: Update `getServerModeArgs()` when available
|
||
2. **Request Batching**: Queue and batch multiple requests
|
||
3. **Connection Pooling**: Maintain pool of persistent connections
|
||
4. **Load Balancing**: Distribute across multiple OpenCode instances
|
||
5. **Health Checks**: Monitor and restart unresponsive instances
|
||
|
||
## Summary
|
||
|
||
The OpenCode Process Manager provides:
|
||
- ✅ Centralized session management
|
||
- ✅ Comprehensive execution tracking
|
||
- ✅ Foundation for future optimization
|
||
- ✅ Graceful fallback to current behavior
|
||
- ✅ Enhanced monitoring and debugging
|
||
|
||
While currently operating in per-session mode, it's ready to leverage OpenCode's server mode as soon as it becomes available, providing significant resource savings and performance improvements.
|