feat(process): make listings deterministic

This commit is contained in:
Virgil 2026-04-04 00:32:12 +00:00
parent 24f853631d
commit eeca66240a
4 changed files with 40 additions and 3 deletions

View file

@ -4,6 +4,7 @@ import (
"encoding/json"
"os"
"path/filepath"
"sort"
"strings"
"syscall"
"time"
@ -125,6 +126,16 @@ func (r *Registry) List() ([]DaemonEntry, error) {
alive = append(alive, entry)
}
sort.Slice(alive, func(i, j int) bool {
if alive[i].Started.Equal(alive[j].Started) {
if alive[i].Code == alive[j].Code {
return alive[i].Daemon < alive[j].Daemon
}
return alive[i].Code < alive[j].Code
}
return alive[i].Started.Before(alive[j].Started)
})
return alive, nil
}

View file

@ -76,7 +76,9 @@ func TestRegistry_List(t *testing.T) {
entries, err := reg.List()
require.NoError(t, err)
assert.Len(t, entries, 2)
require.Len(t, entries, 2)
assert.Equal(t, "app1", entries[0].Code)
assert.Equal(t, "app2", entries[1].Code)
}
func TestRegistry_List_PrunesStale(t *testing.T) {

View file

@ -7,6 +7,7 @@ import (
"fmt"
"io"
"os/exec"
"sort"
"sync"
"sync/atomic"
"syscall"
@ -311,6 +312,7 @@ func (s *Service) List() []*Process {
for _, p := range s.processes {
result = append(result, p)
}
sortProcesses(result)
return result
}
@ -325,6 +327,7 @@ func (s *Service) Running() []*Process {
result = append(result, p)
}
}
sortProcesses(result)
return result
}
@ -488,3 +491,13 @@ func classifyProcessExit(err error) (Status, int, error, string) {
return StatusFailed, 0, err, ""
}
// sortProcesses orders processes by start time, then ID for stable output.
func sortProcesses(procs []*Process) {
sort.Slice(procs, func(i, j int) bool {
if procs[i].StartedAt.Equal(procs[j].StartedAt) {
return procs[i].ID < procs[j].ID
}
return procs[i].StartedAt.Before(procs[j].StartedAt)
})
}

View file

@ -341,6 +341,8 @@ func TestService_List(t *testing.T) {
list := svc.List()
assert.Len(t, list, 2)
assert.Equal(t, proc1.ID, list[0].ID)
assert.Equal(t, proc2.ID, list[1].ID)
})
t.Run("get by id", func(t *testing.T) {
@ -583,15 +585,24 @@ func TestService_Running(t *testing.T) {
proc1, err := svc.Start(ctx, "sleep", "60")
require.NoError(t, err)
proc2, err := svc.Start(context.Background(), "echo", "done")
doneProc, err := svc.Start(context.Background(), "echo", "done")
require.NoError(t, err)
<-proc2.Done()
<-doneProc.Done()
running := svc.Running()
assert.Len(t, running, 1)
assert.Equal(t, proc1.ID, running[0].ID)
proc2, err := svc.Start(ctx, "sleep", "60")
require.NoError(t, err)
running = svc.Running()
assert.Len(t, running, 2)
assert.Equal(t, proc1.ID, running[0].ID)
assert.Equal(t, proc2.ID, running[1].ID)
cancel()
<-proc1.Done()
<-proc2.Done()
})
}