Documentation
¶
Index ¶
- Constants
- Variables
- type ManagedProcess
- func (p *ManagedProcess) Cancel()
- func (p *ManagedProcess) CombinedOutput() ([]byte, bool)
- func (p *ManagedProcess) CompareAndSwapState(expected, new ProcessState) bool
- func (p *ManagedProcess) Done() <-chan struct{}
- func (p *ManagedProcess) EndTime() *time.Time
- func (p *ManagedProcess) ExitCode() int
- func (p *ManagedProcess) IsDone() bool
- func (p *ManagedProcess) IsRunning() bool
- func (p *ManagedProcess) PID() int
- func (p *ManagedProcess) Runtime() time.Duration
- func (p *ManagedProcess) SetState(s ProcessState)
- func (p *ManagedProcess) StartTime() *time.Time
- func (p *ManagedProcess) State() ProcessState
- func (p *ManagedProcess) Stderr() ([]byte, bool)
- func (p *ManagedProcess) Stdout() ([]byte, bool)
- func (p *ManagedProcess) Summary() string
- type ManagerConfig
- type ProcessConfig
- type ProcessManager
- func (pm *ProcessManager) ActiveCount() int64
- func (pm *ProcessManager) Config() ManagerConfig
- func (pm *ProcessManager) Get(id string) (*ManagedProcess, error)
- func (pm *ProcessManager) GetByPID(pid int) *ManagedProcess
- func (pm *ProcessManager) GetByPath(id, projectPath string) (*ManagedProcess, error)
- func (pm *ProcessManager) IncrementFailed()
- func (pm *ProcessManager) IsManagedPID(pid int) bool
- func (pm *ProcessManager) IsShuttingDown() bool
- func (pm *ProcessManager) KillProcessByPort(ctx context.Context, port int) ([]int, error)
- func (pm *ProcessManager) List() []*ManagedProcess
- func (pm *ProcessManager) ListByLabel(key, value string) []*ManagedProcess
- func (pm *ProcessManager) Register(proc *ManagedProcess) error
- func (pm *ProcessManager) Remove(id string) bool
- func (pm *ProcessManager) RemoveByPath(id, projectPath string) bool
- func (pm *ProcessManager) Restart(ctx context.Context, id string) (*ManagedProcess, error)
- func (pm *ProcessManager) RunSync(ctx context.Context, cfg ProcessConfig) (int, error)
- func (pm *ProcessManager) Shutdown(ctx context.Context) error
- func (pm *ProcessManager) Start(ctx context.Context, proc *ManagedProcess) error
- func (pm *ProcessManager) StartCommand(ctx context.Context, cfg ProcessConfig) (*ManagedProcess, error)
- func (pm *ProcessManager) StartOrReuse(ctx context.Context, cfg ProcessConfig) (*StartOrReuseResult, error)
- func (pm *ProcessManager) Stop(ctx context.Context, id string) error
- func (pm *ProcessManager) StopProcess(ctx context.Context, proc *ManagedProcess) error
- func (pm *ProcessManager) TotalFailed() int64
- func (pm *ProcessManager) TotalStarted() int64
- type ProcessState
- type RingBuffer
- type StartOrReuseResult
Constants ¶
const DefaultBufferSize = 256 * 1024
DefaultBufferSize is the default capacity for ring buffers (256KB)
Variables ¶
var ( // ErrProcessExists is returned when trying to register a process with an existing ID. ErrProcessExists = errors.New("process already exists") // ErrProcessNotFound is returned when a process ID is not found. ErrProcessNotFound = errors.New("process not found") // ErrInvalidState is returned when an operation is invalid for the current state. ErrInvalidState = errors.New("invalid process state for operation") // ErrShuttingDown is returned when the manager is shutting down. ErrShuttingDown = errors.New("process manager is shutting down") )
Functions ¶
This section is empty.
Types ¶
type ManagedProcess ¶
type ManagedProcess struct {
// ID is the unique identifier for this process.
ID string
// ProjectPath is the working directory for the process.
ProjectPath string
// Command is the executable to run.
Command string
// Args are the command arguments.
Args []string
// Labels provide metadata for filtering/grouping.
Labels map[string]string
// contains filtered or unexported fields
}
ManagedProcess represents a subprocess managed by the MCP server.
func NewManagedProcess ¶
func NewManagedProcess(cfg ProcessConfig) *ManagedProcess
NewManagedProcess creates a new ManagedProcess from config. The process is in StatePending and must be started with ProcessManager.Start().
func (*ManagedProcess) Cancel ¶
func (p *ManagedProcess) Cancel()
Cancel signals the process to stop via context cancellation.
func (*ManagedProcess) CombinedOutput ¶
func (p *ManagedProcess) CombinedOutput() ([]byte, bool)
CombinedOutput returns both stdout and stderr concatenated. Note: Order is stdout then stderr, not chronological interleaving.
func (*ManagedProcess) CompareAndSwapState ¶
func (p *ManagedProcess) CompareAndSwapState(expected, new ProcessState) bool
CompareAndSwapState atomically updates state if it matches expected. Returns true if the swap succeeded.
func (*ManagedProcess) Done ¶
func (p *ManagedProcess) Done() <-chan struct{}
Done returns a channel that is closed when the process completes.
func (*ManagedProcess) EndTime ¶
func (p *ManagedProcess) EndTime() *time.Time
EndTime returns when the process stopped, or nil if still running.
func (*ManagedProcess) ExitCode ¶
func (p *ManagedProcess) ExitCode() int
ExitCode returns the exit code, or -1 if not finished.
func (*ManagedProcess) IsDone ¶
func (p *ManagedProcess) IsDone() bool
IsDone returns true if the process has finished (stopped or failed).
func (*ManagedProcess) IsRunning ¶
func (p *ManagedProcess) IsRunning() bool
IsRunning returns true if the process is currently running.
func (*ManagedProcess) PID ¶
func (p *ManagedProcess) PID() int
PID returns the OS process ID, or -1 if not started.
func (*ManagedProcess) Runtime ¶
func (p *ManagedProcess) Runtime() time.Duration
Runtime returns how long the process has been running (or ran).
func (*ManagedProcess) SetState ¶
func (p *ManagedProcess) SetState(s ProcessState)
SetState sets the process state.
func (*ManagedProcess) StartTime ¶
func (p *ManagedProcess) StartTime() *time.Time
StartTime returns when the process was started, or nil if not started.
func (*ManagedProcess) State ¶
func (p *ManagedProcess) State() ProcessState
State returns the current process state (lock-free atomic read).
func (*ManagedProcess) Stderr ¶
func (p *ManagedProcess) Stderr() ([]byte, bool)
Stderr returns a snapshot of the stderr buffer.
func (*ManagedProcess) Stdout ¶
func (p *ManagedProcess) Stdout() ([]byte, bool)
Stdout returns a snapshot of the stdout buffer.
func (*ManagedProcess) Summary ¶
func (p *ManagedProcess) Summary() string
Summary returns a brief status summary suitable for LLM consumption.
type ManagerConfig ¶
type ManagerConfig struct {
// DefaultTimeout is the default process timeout (0 = no timeout).
DefaultTimeout time.Duration
// MaxOutputBuffer is the per-stream buffer size in bytes.
MaxOutputBuffer int
// GracefulTimeout is how long to wait for graceful shutdown before SIGKILL.
GracefulTimeout time.Duration
// HealthCheckPeriod is how often to check process health (0 = disabled).
HealthCheckPeriod time.Duration
}
ManagerConfig holds configuration for the ProcessManager.
func DefaultManagerConfig ¶
func DefaultManagerConfig() ManagerConfig
DefaultManagerConfig returns a ManagerConfig with sensible defaults.
type ProcessConfig ¶
type ProcessConfig struct {
ID string
ProjectPath string
Command string
Args []string
Labels map[string]string
BufferSize int // Per-stream buffer size (0 = default)
Timeout time.Duration // 0 = no timeout
}
ProcessConfig holds configuration for creating a new process.
type ProcessManager ¶
type ProcessManager struct {
// contains filtered or unexported fields
}
ProcessManager manages all spawned processes with lock-free access.
func NewProcessManager ¶
func NewProcessManager(config ManagerConfig) *ProcessManager
NewProcessManager creates a new ProcessManager with the given configuration.
func (*ProcessManager) ActiveCount ¶
func (pm *ProcessManager) ActiveCount() int64
ActiveCount returns the number of registered processes.
func (*ProcessManager) Config ¶
func (pm *ProcessManager) Config() ManagerConfig
Config returns the manager configuration.
func (*ProcessManager) Get ¶
func (pm *ProcessManager) Get(id string) (*ManagedProcess, error)
Get retrieves a process by ID and project path (lock-free read).
func (*ProcessManager) GetByPID ¶
func (pm *ProcessManager) GetByPID(pid int) *ManagedProcess
GetByPID returns the managed process with the given OS PID, or nil if not found.
func (*ProcessManager) GetByPath ¶
func (pm *ProcessManager) GetByPath(id, projectPath string) (*ManagedProcess, error)
GetByPath retrieves a process by ID and project path (lock-free read).
func (*ProcessManager) IncrementFailed ¶
func (pm *ProcessManager) IncrementFailed()
IncrementFailed increments the failed process counter.
func (*ProcessManager) IsManagedPID ¶
func (pm *ProcessManager) IsManagedPID(pid int) bool
IsManagedPID returns true if the given PID belongs to a running managed process.
func (*ProcessManager) IsShuttingDown ¶
func (pm *ProcessManager) IsShuttingDown() bool
IsShuttingDown returns true if the manager is shutting down.
func (*ProcessManager) KillProcessByPort ¶
KillProcessByPort finds and kills processes listening on the specified port. This is useful for cleaning up orphaned processes that are blocking port reuse. Returns the PIDs of killed processes and any error.
func (*ProcessManager) List ¶
func (pm *ProcessManager) List() []*ManagedProcess
List returns all managed processes. Note: This is not a consistent snapshot due to sync.Map semantics.
func (*ProcessManager) ListByLabel ¶
func (pm *ProcessManager) ListByLabel(key, value string) []*ManagedProcess
ListByLabel returns processes matching the given label key/value.
func (*ProcessManager) Register ¶
func (pm *ProcessManager) Register(proc *ManagedProcess) error
Register adds a new process to the registry. Returns ErrProcessExists if a process with the same ID+ProjectPath already exists.
func (*ProcessManager) Remove ¶
func (pm *ProcessManager) Remove(id string) bool
Remove deletes a process from the registry by ID (searches all paths). Returns true if the process was found and removed.
func (*ProcessManager) RemoveByPath ¶
func (pm *ProcessManager) RemoveByPath(id, projectPath string) bool
RemoveByPath deletes a process from the registry by ID and path. Returns true if the process was found and removed.
func (*ProcessManager) Restart ¶
func (pm *ProcessManager) Restart(ctx context.Context, id string) (*ManagedProcess, error)
Restart stops a process and starts a new one with the same configuration.
func (*ProcessManager) RunSync ¶
func (pm *ProcessManager) RunSync(ctx context.Context, cfg ProcessConfig) (int, error)
RunSync starts a process and waits for it to complete. Returns the exit code and any error.
func (*ProcessManager) Shutdown ¶
func (pm *ProcessManager) Shutdown(ctx context.Context) error
Shutdown gracefully stops all managed processes. It blocks until all processes are stopped or the context is cancelled. If the context has a very short deadline (<3s), immediately sends SIGKILL to all processes.
func (*ProcessManager) Start ¶
func (pm *ProcessManager) Start(ctx context.Context, proc *ManagedProcess) error
Start begins execution of a process. The process must be in StatePending.
func (*ProcessManager) StartCommand ¶
func (pm *ProcessManager) StartCommand(ctx context.Context, cfg ProcessConfig) (*ManagedProcess, error)
StartCommand is a convenience method to create and start a process.
func (*ProcessManager) StartOrReuse ¶
func (pm *ProcessManager) StartOrReuse(ctx context.Context, cfg ProcessConfig) (*StartOrReuseResult, error)
StartOrReuse implements idempotent process start with auto port conflict resolution: - If a process with the same ID+ProjectPath is running, return it - If a process with the same ID+ProjectPath is stopped/failed, remove it and start new - If no process exists, start a new one - If process fails quickly due to port conflict (EADDRINUSE), kill blocker and retry once
func (*ProcessManager) Stop ¶
func (pm *ProcessManager) Stop(ctx context.Context, id string) error
Stop terminates a process gracefully, falling back to force kill.
func (*ProcessManager) StopProcess ¶
func (pm *ProcessManager) StopProcess(ctx context.Context, proc *ManagedProcess) error
StopProcess terminates the given process.
func (*ProcessManager) TotalFailed ¶
func (pm *ProcessManager) TotalFailed() int64
TotalFailed returns the total number of processes that failed.
func (*ProcessManager) TotalStarted ¶
func (pm *ProcessManager) TotalStarted() int64
TotalStarted returns the total number of processes ever started.
type ProcessState ¶
type ProcessState uint32
ProcessState represents the lifecycle state of a managed process.
const ( // StatePending is the initial state before the process is started. StatePending ProcessState = iota // StateStarting indicates the process is being started. StateStarting // StateRunning indicates the process is actively running. StateRunning // StateStopping indicates the process is being stopped. StateStopping // StateStopped indicates the process has stopped normally. StateStopped // StateFailed indicates the process exited with an error. StateFailed )
func (ProcessState) String ¶
func (s ProcessState) String() string
String returns a human-readable state name.
type RingBuffer ¶
type RingBuffer struct {
// contains filtered or unexported fields
}
RingBuffer is a thread-safe circular buffer for process output. It bounds memory usage by discarding oldest data when full.
func NewRingBuffer ¶
func NewRingBuffer(capacity int) *RingBuffer
NewRingBuffer creates a new ring buffer with the specified capacity. If capacity <= 0, DefaultBufferSize is used.
func (*RingBuffer) Len ¶
func (rb *RingBuffer) Len() int
Len returns the current number of bytes stored (up to capacity).
func (*RingBuffer) Snapshot ¶
func (rb *RingBuffer) Snapshot() (data []byte, truncated bool)
Snapshot returns a copy of the current buffer contents. Returns (data, truncated) where truncated indicates data loss. Thread-safe for concurrent reads.
func (*RingBuffer) Truncated ¶
func (rb *RingBuffer) Truncated() bool
Truncated returns whether any data has been lost due to overflow.
type StartOrReuseResult ¶
type StartOrReuseResult struct {
Process *ManagedProcess
Reused bool // True if an existing running process was returned
Cleaned bool // True if a stopped/failed process was cleaned up before starting
PortRetried bool // True if a port conflict was detected and resolved
PortsCleared []int // Ports that were cleared due to conflicts
PortError string // Non-empty if port conflict couldn't be resolved (e.g., managed process blocking)
}
StartOrReuseResult contains the result of StartOrReuse operation.