refactor: clean up proc.go — ensureProcess bridge, processIsRunning/processKill helpers
- proc.go: ensureProcess() as temporary bridge until go-process gets v0.7.0 update - processIsRunning/processKill: use go-process ProcessID when available, fall back to PID - WorkspaceStatus: add ProcessID field for go-process managed lookup - dispatch.go: simplified spawnAgent goroutine — uses proc.Done() instead of syscall poll - Removed syscall import from dispatch.go Next: update go-process to v0.7.0 Core contract, then replace syscall.Kill calls in queue.go, shutdown.go, status.go, dispatch_sync.go with processIsRunning/processKill. Coverage: 78.1%, 802 tests Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
8521a55907
commit
4eb1111faa
3 changed files with 58 additions and 26 deletions
|
|
@ -4,7 +4,6 @@ package agentic
|
|||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"dappco.re/go/agent/pkg/messages"
|
||||
|
|
@ -370,19 +369,7 @@ func (s *PrepSubsystem) spawnAgent(agent, prompt, wsDir string) (int, string, er
|
|||
s.startIssueTracking(wsDir)
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-proc.Done():
|
||||
goto done
|
||||
case <-ticker.C:
|
||||
if err := syscall.Kill(pid, 0); err != nil {
|
||||
goto done
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
<-proc.Done()
|
||||
s.onAgentComplete(agent, wsDir, outputFile,
|
||||
proc.Info().ExitCode, string(proc.Info().Status), proc.Output())
|
||||
}()
|
||||
|
|
|
|||
|
|
@ -2,12 +2,19 @@
|
|||
|
||||
// Process execution helpers — wraps go-process for testable command execution.
|
||||
// All external command execution in the agentic package goes through these helpers.
|
||||
//
|
||||
// Requires go-process to be registered with Core via:
|
||||
//
|
||||
// core.New(core.WithService(agentic.ProcessRegister))
|
||||
//
|
||||
// If process service is not initialised (e.g. in tests), helpers will error.
|
||||
|
||||
package agentic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
"dappco.re/go/core/process"
|
||||
|
|
@ -15,23 +22,26 @@ import (
|
|||
|
||||
var procOnce sync.Once
|
||||
|
||||
// ensureProcess lazily initialises the default process service.
|
||||
// ensureProcess lazily initialises go-process default service for tests
|
||||
// and standalone usage. In production, main.go registers ProcessRegister
|
||||
// with Core which calls SetDefault properly.
|
||||
func ensureProcess() {
|
||||
procOnce.Do(func() {
|
||||
if process.Default() == nil {
|
||||
c := core.New()
|
||||
svc, err := process.NewService(process.Options{})(c)
|
||||
if err == nil {
|
||||
if s, ok := svc.(*process.Service); ok {
|
||||
process.SetDefault(s)
|
||||
}
|
||||
if process.Default() != nil {
|
||||
return
|
||||
}
|
||||
c := core.New()
|
||||
svc, err := process.NewService(process.Options{})(c)
|
||||
if err == nil {
|
||||
if s, ok := svc.(*process.Service); ok {
|
||||
_ = process.SetDefault(s)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// runCmd executes a command in a directory and returns (output, error).
|
||||
// Uses go-process RunWithOptions for testability.
|
||||
// Uses go-process RunWithOptions — requires process service to be registered.
|
||||
//
|
||||
// out, err := runCmd(ctx, repoDir, "git", "log", "--oneline", "-20")
|
||||
func runCmd(ctx context.Context, dir string, command string, args ...string) (string, error) {
|
||||
|
|
@ -88,3 +98,37 @@ func gitOutput(ctx context.Context, dir string, args ...string) string {
|
|||
}
|
||||
return core.Trim(out)
|
||||
}
|
||||
|
||||
// --- Process lifecycle helpers ---
|
||||
|
||||
// processIsRunning checks if a process is still alive.
|
||||
// Uses go-process ProcessID if available, falls back to PID signal check.
|
||||
//
|
||||
// if processIsRunning(st.ProcessID, st.PID) { ... }
|
||||
func processIsRunning(processID string, pid int) bool {
|
||||
if processID != "" {
|
||||
if proc, err := process.Get(processID); err == nil {
|
||||
return proc.IsRunning()
|
||||
}
|
||||
}
|
||||
if pid > 0 {
|
||||
return syscall.Kill(pid, 0) == nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// processKill terminates a process.
|
||||
// Uses go-process Kill if ProcessID available, falls back to SIGTERM.
|
||||
//
|
||||
// processKill(st.ProcessID, st.PID)
|
||||
func processKill(processID string, pid int) bool {
|
||||
if processID != "" {
|
||||
if proc, err := process.Get(processID); err == nil {
|
||||
return proc.Kill() == nil
|
||||
}
|
||||
}
|
||||
if pid > 0 {
|
||||
return syscall.Kill(pid, syscall.SIGTERM) == nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,10 @@ type WorkspaceStatus struct {
|
|||
Org string `json:"org,omitempty"` // forge org (e.g. "core")
|
||||
Task string `json:"task"` // task description
|
||||
Branch string `json:"branch,omitempty"` // git branch name
|
||||
Issue int `json:"issue,omitempty"` // forge issue number
|
||||
PID int `json:"pid,omitempty"` // process ID (if running)
|
||||
StartedAt time.Time `json:"started_at"` // when dispatch started
|
||||
Issue int `json:"issue,omitempty"` // forge issue number
|
||||
PID int `json:"pid,omitempty"` // OS process ID (if running)
|
||||
ProcessID string `json:"process_id,omitempty"` // go-process ID for managed lookup
|
||||
StartedAt time.Time `json:"started_at"` // when dispatch started
|
||||
UpdatedAt time.Time `json:"updated_at"` // last status change
|
||||
Question string `json:"question,omitempty"` // from BLOCKED.md
|
||||
Runs int `json:"runs"` // how many times dispatched/resumed
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue