platform/doc/process_package_specification.md
2024-11-25 20:33:45 -07:00

408 lines
10 KiB
Markdown

# Process Package Specification
## Overview
The Process package provides a robust system process handling system that matches Laravel's process functionality. It supports process execution, input/output handling, process pools, and signal handling while integrating with our Event and Queue packages.
> **Related Documentation**
> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status
> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns
> - See [Testing Guide](testing_guide.md) for testing approaches
> - See [Getting Started Guide](getting_started.md) for development setup
> - See [Events Package Specification](events_package_specification.md) for process events
> - See [Queue Package Specification](queue_package_specification.md) for background processing
## Core Features
### 1. Process Manager
```dart
/// Core process manager implementation
class ProcessManager implements ProcessContract {
/// Container instance
final Container _container;
/// Active processes
final Map<int, Process> _processes = {};
/// Process event dispatcher
final EventDispatcherContract _events;
ProcessManager(this._container, this._events);
/// Starts a process
Future<Process> start(
String command, [
List<String>? arguments,
ProcessOptions? options
]) async {
options ??= ProcessOptions();
var process = await Process.start(
command,
arguments ?? [],
workingDirectory: options.workingDirectory,
environment: options.environment,
includeParentEnvironment: options.includeParentEnvironment,
runInShell: options.runInShell
);
_processes[process.pid] = process;
await _events.dispatch(ProcessStarted(process));
return process;
}
/// Runs a process to completion
Future<ProcessResult> run(
String command, [
List<String>? arguments,
ProcessOptions? options
]) async {
var process = await start(command, arguments, options);
var result = await process.exitCode;
await _events.dispatch(ProcessCompleted(
process,
result
));
return ProcessResult(
process.pid,
result,
await _readOutput(process.stdout),
await _readOutput(process.stderr)
);
}
/// Kills a process
Future<void> kill(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) async {
var process = _processes[pid];
if (process == null) return;
process.kill(signal);
await _events.dispatch(ProcessKilled(process));
_processes.remove(pid);
}
/// Gets active processes
List<Process> get activeProcesses => List.from(_processes.values);
/// Reads process output
Future<String> _readOutput(Stream<List<int>> stream) async {
var buffer = StringBuffer();
await for (var data in stream) {
buffer.write(String.fromCharCodes(data));
}
return buffer.toString();
}
}
```
### 2. Process Pool
```dart
/// Process pool for parallel execution
class ProcessPool {
/// Maximum concurrent processes
final int concurrency;
/// Process manager
final ProcessManager _manager;
/// Active processes
final Set<Process> _active = {};
/// Pending commands
final Queue<PendingCommand> _pending = Queue();
ProcessPool(this._manager, {this.concurrency = 5});
/// Starts a process in the pool
Future<ProcessResult> start(
String command, [
List<String>? arguments,
ProcessOptions? options
]) async {
var pending = PendingCommand(
command,
arguments,
options
);
_pending.add(pending);
await _processQueue();
return await pending.future;
}
/// Processes pending commands
Future<void> _processQueue() async {
while (_active.length < concurrency && _pending.isNotEmpty) {
var command = _pending.removeFirst();
await _startProcess(command);
}
}
/// Starts a process
Future<void> _startProcess(PendingCommand command) async {
var process = await _manager.start(
command.command,
command.arguments,
command.options
);
_active.add(process);
process.exitCode.then((result) {
_active.remove(process);
command.complete(ProcessResult(
process.pid,
result,
'',
''
));
_processQueue();
});
}
}
```
### 3. Process Events
```dart
/// Process started event
class ProcessStarted {
/// The started process
final Process process;
ProcessStarted(this.process);
}
/// Process completed event
class ProcessCompleted {
/// The completed process
final Process process;
/// Exit code
final int exitCode;
ProcessCompleted(this.process, this.exitCode);
}
/// Process killed event
class ProcessKilled {
/// The killed process
final Process process;
ProcessKilled(this.process);
}
/// Process failed event
class ProcessFailed {
/// The failed process
final Process process;
/// Error details
final Object error;
ProcessFailed(this.process, this.error);
}
```
### 4. Process Options
```dart
/// Process execution options
class ProcessOptions {
/// Working directory
final String? workingDirectory;
/// Environment variables
final Map<String, String>? environment;
/// Include parent environment
final bool includeParentEnvironment;
/// Run in shell
final bool runInShell;
/// Process timeout
final Duration? timeout;
/// Idle timeout
final Duration? idleTimeout;
/// Retry attempts
final int retryAttempts;
/// Retry delay
final Duration retryDelay;
ProcessOptions({
this.workingDirectory,
this.environment,
this.includeParentEnvironment = true,
this.runInShell = false,
this.timeout,
this.idleTimeout,
this.retryAttempts = 0,
this.retryDelay = const Duration(seconds: 1)
});
}
```
## Integration Examples
### 1. Basic Process Execution
```dart
// Run process
var result = await processManager.run('ls', ['-la']);
print('Output: ${result.stdout}');
print('Exit code: ${result.exitCode}');
// Start long-running process
var process = await processManager.start('server', ['--port=8080']);
await process.exitCode; // Wait for completion
```
### 2. Process Pool
```dart
// Create process pool
var pool = ProcessPool(processManager, concurrency: 3);
// Run multiple processes
await Future.wait([
pool.start('task1'),
pool.start('task2'),
pool.start('task3'),
pool.start('task4') // Queued until slot available
]);
```
### 3. Process Events
```dart
// Listen for process events
events.listen<ProcessStarted>((event) {
print('Process ${event.process.pid} started');
});
events.listen<ProcessCompleted>((event) {
print('Process ${event.process.pid} completed with code ${event.exitCode}');
});
// Start process
await processManager.start('long-task');
```
## Testing
```dart
void main() {
group('Process Manager', () {
test('runs processes', () async {
var manager = ProcessManager(container, events);
var result = await manager.run('echo', ['Hello']);
expect(result.exitCode, equals(0));
expect(result.stdout, contains('Hello'));
});
test('handles process failure', () async {
var manager = ProcessManager(container, events);
expect(
() => manager.run('invalid-command'),
throwsA(isA<ProcessException>())
);
});
});
group('Process Pool', () {
test('limits concurrent processes', () async {
var pool = ProcessPool(manager, concurrency: 2);
var started = <String>[];
events.listen<ProcessStarted>((event) {
started.add(event.process.pid.toString());
});
await Future.wait([
pool.start('task1'),
pool.start('task2'),
pool.start('task3')
]);
expect(started.length, equals(3));
expect(started.take(2).length, equals(2));
});
});
}
```
## Next Steps
1. Implement core process features
2. Add process pool
3. Add process events
4. Add retry handling
5. Write tests
6. Add benchmarks
## Development Guidelines
### 1. Getting Started
Before implementing process features:
1. Review [Getting Started Guide](getting_started.md)
2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md)
3. Follow [Testing Guide](testing_guide.md)
4. Use [Foundation Integration Guide](foundation_integration_guide.md)
5. Review [Events Package Specification](events_package_specification.md)
6. Review [Queue Package Specification](queue_package_specification.md)
### 2. Implementation Process
For each process feature:
1. Write tests following [Testing Guide](testing_guide.md)
2. Implement following Laravel patterns
3. Document following [Getting Started Guide](getting_started.md#documentation)
4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md)
### 3. Quality Requirements
All implementations must:
1. Pass all tests (see [Testing Guide](testing_guide.md))
2. Meet Laravel compatibility requirements
3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md))
4. Support event integration (see [Events Package Specification](events_package_specification.md))
5. Support queue integration (see [Queue Package Specification](queue_package_specification.md))
### 4. Integration Considerations
When implementing process features:
1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md)
2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md)
3. Use testing approaches from [Testing Guide](testing_guide.md)
4. Follow development setup in [Getting Started Guide](getting_started.md)
### 5. Performance Guidelines
Process system must:
1. Handle concurrent processes efficiently
2. Manage system resources
3. Support process pooling
4. Scale with process count
5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks)
### 6. Testing Requirements
Process tests must:
1. Cover all process operations
2. Test concurrent execution
3. Verify event handling
4. Check resource cleanup
5. Follow patterns in [Testing Guide](testing_guide.md)
### 7. Documentation Requirements
Process documentation must:
1. Explain process patterns
2. Show pool examples
3. Cover error handling
4. Include performance tips
5. Follow standards in [Getting Started Guide](getting_started.md#documentation)