Documentation
¶
Overview ¶
Package bgproc manages background processes started by the agent.
The manager is deliberately process-scoped, not agent-scoped: agents are created per run (serve headless), per message (Telegram), and per REPL session, while background jobs must outlive the turn that started them. One Manager lives for the lifetime of the odek process; jobs are keyed by session id so concurrent sessions never see each other's jobs.
Lifecycle contract (v1):
- A job runs until it exits, its timeout fires, or it is stopped.
- StopAll(session) runs at session teardown; Shutdown() at process exit.
- There is no detach mode: every job is killed when its session or the process ends. Detached processes are an explicit non-goal (v1).
Security contract:
- Output is captured into a bounded in-memory ring — never spilled to disk, never persisted, never included in events (arg-hash discipline lives in the events package).
- All addressing calls take the session id; a foreign session gets the same "not found" answer as a stale id (no existence oracle).
- Stop signals the process GROUP (SIGTERM, then SIGKILL after a grace window) so shell-spawned children die with the job; sandbox mode wraps the command via the caller-supplied SandboxWrap (the shell tool's pidfile mechanism) and runs the follow-up kill after a forced stop.
Index ¶
- Variables
- type Config
- type Job
- type Manager
- func (m *Manager) DrainNotices(sessionID string) []Notice
- func (m *Manager) Get(sessionID, jobID string) (Job, bool)
- func (m *Manager) List(sessionID string) []Job
- func (m *Manager) Output(sessionID, jobID string, since int64, limit int) (string, int64, error)
- func (m *Manager) Shutdown() []Job
- func (m *Manager) Start(sessionID, command, cwd string, timeout time.Duration) (*Job, error)
- func (m *Manager) Stop(sessionID, jobID string) (Job, bool)
- func (m *Manager) StopAll(sessionID string) []Job
- type Notice
- type Observer
- type Status
Constants ¶
This section is empty.
Variables ¶
var ErrTooManyJobs = errors.New("background job limit reached for session")
ErrTooManyJobs is returned by Start when the session already has MaxJobsPerSession jobs running.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// MaxJobsPerSession caps concurrently running jobs per session.
// <= 0 means unlimited (not recommended; callers should clamp).
MaxJobsPerSession int
// MaxOutputBytes caps the per-job output ring. <= 0 means 1 MiB.
MaxOutputBytes int
// MaxTimeout, when > 0, clamps the per-job timeout passed to Start.
MaxTimeout time.Duration
// SandboxWrap, when set, rewrites the command into a sandboxed argv
// (e.g. the shell tool's docker-exec pidfile wrapper) and returns a
// follow-up func invoked after the job is forcibly stopped. When nil,
// commands run on the host via "sh -c".
SandboxWrap func(command string) (argv []string, followUp func(), err error)
}
Config bounds the manager.
type Job ¶
type Job struct {
ID string
SessionID string
Command string
Status Status
ExitCode int // meaningful once ended (bash semantics; -1 when signaled)
Err string // terminal error detail, when applicable
StartedAt time.Time
EndedAt time.Time
Timeout time.Duration // 0 = until session end
OutputBytes int64 // logical output size (dropped-front + retained); populated by Get snapshots
}
Job is a snapshot of a background job's state.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns every background job of the process.
func NewManager ¶
NewManager returns a manager with the given bounds and observer (both may be zero/nil, applying defaults).
func (*Manager) DrainNotices ¶
DrainNotices pops all pending completion notices for the session.
func (*Manager) Get ¶
Get returns the job snapshot; ok is false for unknown or foreign ids. The snapshot carries the job's logical output size so callers can judge whether reading the output is worthwhile (B3-TOOLS-3).
func (*Manager) Output ¶
Output returns up to limit bytes of output recorded after the absolute byte offset since (limit <= 0 = no cap), plus the cursor for the next read. When the ring has dropped bytes from the front, a truncation marker precedes the retained window. Foreign or unknown ids yield an error identical in shape for both cases.
func (*Manager) Start ¶
Start spawns command in the given session and returns immediately. timeout > 0 kills the job (StatusTimeout) when it elapses; 0 means the job runs until session end. The returned snapshot has Status running.
type Notice ¶
type Notice struct {
JobID string
SessionID string
Command string
Status Status
ExitCode int
Duration time.Duration
OutputBytes int64
Tail string // last output, rune-boundary-safe
}
Notice reports a job that reached a terminal state. It is delivered to the session's completion-notice queue (drained by the agent loop at the top of the next iteration) and to the Observer.
type Observer ¶
Observer receives job lifecycle callbacks. Implementations must be non-blocking; they are invoked from the manager's waiter goroutines without the manager lock held.