feat(process): include exit errors in action payloads
This commit is contained in:
parent
9b3dd1ec49
commit
8d8267543d
3 changed files with 44 additions and 7 deletions
|
|
@ -194,7 +194,7 @@ type ActionProcessExited struct {
|
|||
ID string
|
||||
ExitCode int
|
||||
Duration time.Duration
|
||||
Error error // Reserved for future exit metadata; currently left unset by the service
|
||||
Error error // Set for failed starts, non-zero exits, or killed processes.
|
||||
}
|
||||
|
||||
// ActionProcessKilled is broadcast when a process is terminated.
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
|
|||
|
||||
// Start the process
|
||||
if err := cmd.Start(); err != nil {
|
||||
startErr := coreerr.E("Service.StartWithOptions", "failed to start process", err)
|
||||
proc.mu.Lock()
|
||||
proc.Status = StatusFailed
|
||||
proc.ExitCode = -1
|
||||
|
|
@ -232,10 +233,10 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
|
|||
ID: id,
|
||||
ExitCode: -1,
|
||||
Duration: proc.Duration,
|
||||
Error: nil,
|
||||
Error: startErr,
|
||||
})
|
||||
}
|
||||
return proc, coreerr.E("Service.StartWithOptions", "failed to start process", err)
|
||||
return proc, startErr
|
||||
}
|
||||
|
||||
proc.mu.Lock()
|
||||
|
|
@ -291,7 +292,7 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
|
|||
err := cmd.Wait()
|
||||
|
||||
duration := time.Since(proc.StartedAt)
|
||||
status, exitCode, _, signalName := classifyProcessExit(err)
|
||||
status, exitCode, exitErr, signalName := classifyProcessExit(err)
|
||||
|
||||
proc.mu.Lock()
|
||||
proc.Duration = duration
|
||||
|
|
@ -309,7 +310,7 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
|
|||
ID: id,
|
||||
ExitCode: exitCode,
|
||||
Duration: duration,
|
||||
Error: nil,
|
||||
Error: exitErr,
|
||||
}
|
||||
|
||||
if c := s.coreApp(); c != nil {
|
||||
|
|
|
|||
|
|
@ -337,7 +337,8 @@ func TestService_Actions(t *testing.T) {
|
|||
defer mu.Unlock()
|
||||
assert.Len(t, exited, 1)
|
||||
assert.Equal(t, proc.ID, exited[0].ID)
|
||||
assert.Nil(t, exited[0].Error)
|
||||
require.Error(t, exited[0].Error)
|
||||
assert.Contains(t, exited[0].Error.Error(), "process was killed")
|
||||
assert.Equal(t, StatusKilled, proc.Status)
|
||||
})
|
||||
|
||||
|
|
@ -370,7 +371,42 @@ func TestService_Actions(t *testing.T) {
|
|||
defer mu.Unlock()
|
||||
require.Len(t, exited, 1)
|
||||
assert.Equal(t, -1, exited[0].ExitCode)
|
||||
assert.Nil(t, exited[0].Error)
|
||||
require.Error(t, exited[0].Error)
|
||||
assert.Contains(t, exited[0].Error.Error(), "failed to start process")
|
||||
})
|
||||
|
||||
t.Run("broadcasts exited error on non-zero exit", func(t *testing.T) {
|
||||
c := framework.New()
|
||||
|
||||
factory := NewService(Options{})
|
||||
raw, err := factory(c)
|
||||
require.NoError(t, err)
|
||||
svc := raw.(*Service)
|
||||
|
||||
var exited []ActionProcessExited
|
||||
var mu sync.Mutex
|
||||
|
||||
c.RegisterAction(func(cc *framework.Core, msg framework.Message) framework.Result {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if m, ok := msg.(ActionProcessExited); ok {
|
||||
exited = append(exited, m)
|
||||
}
|
||||
return framework.Result{OK: true}
|
||||
})
|
||||
|
||||
proc, err := svc.Start(context.Background(), "sh", "-c", "exit 7")
|
||||
require.NoError(t, err)
|
||||
|
||||
<-proc.Done()
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
require.Len(t, exited, 1)
|
||||
assert.Equal(t, 7, exited[0].ExitCode)
|
||||
require.Error(t, exited[0].Error)
|
||||
assert.Contains(t, exited[0].Error.Error(), "process exited with code 7")
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue