From eeca66240a6c99af8c9cf7f210286f35f8ce557d Mon Sep 17 00:00:00 2001 From: Virgil Date: Sat, 4 Apr 2026 00:32:12 +0000 Subject: [PATCH] feat(process): make listings deterministic --- registry.go | 11 +++++++++++ registry_test.go | 4 +++- service.go | 13 +++++++++++++ service_test.go | 15 +++++++++++++-- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/registry.go b/registry.go index ed7c8eb..006cd23 100644 --- a/registry.go +++ b/registry.go @@ -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 } diff --git a/registry_test.go b/registry_test.go index 108ae28..e442580 100644 --- a/registry_test.go +++ b/registry_test.go @@ -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) { diff --git a/service.go b/service.go index ea4ebc7..5b905e8 100644 --- a/service.go +++ b/service.go @@ -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) + }) +} diff --git a/service_test.go b/service_test.go index bdceddc..a69749c 100644 --- a/service_test.go +++ b/service_test.go @@ -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() }) }