feat(process): emit exit actions consistently
This commit is contained in:
parent
f70e301631
commit
dcf058047e
2 changed files with 59 additions and 11 deletions
31
service.go
31
service.go
|
|
@ -103,6 +103,7 @@ func (s *Service) Start(ctx context.Context, command string, args ...string) (*P
|
|||
// StartWithOptions spawns a process with full configuration.
|
||||
func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Process, error) {
|
||||
id := fmt.Sprintf("proc-%d", s.idCounter.Add(1))
|
||||
startedAt := time.Now()
|
||||
|
||||
if opts.KillGroup && !opts.Detach {
|
||||
return nil, coreerr.E("Service.StartWithOptions", "KillGroup requires Detach", nil)
|
||||
|
|
@ -159,7 +160,7 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
|
|||
Args: opts.Args,
|
||||
Dir: opts.Dir,
|
||||
Env: opts.Env,
|
||||
StartedAt: time.Now(),
|
||||
StartedAt: startedAt,
|
||||
Status: StatusRunning,
|
||||
cmd: cmd,
|
||||
ctx: procCtx,
|
||||
|
|
@ -174,6 +175,14 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
|
|||
// Start the process
|
||||
if err := cmd.Start(); err != nil {
|
||||
cancel()
|
||||
if s.Core() != nil {
|
||||
_ = s.Core().ACTION(ActionProcessExited{
|
||||
ID: id,
|
||||
ExitCode: -1,
|
||||
Duration: time.Since(startedAt),
|
||||
Error: coreerr.E("Service.StartWithOptions", "failed to start process", err),
|
||||
})
|
||||
}
|
||||
return nil, coreerr.E("Service.StartWithOptions", "failed to start process", err)
|
||||
}
|
||||
|
||||
|
|
@ -234,21 +243,21 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
|
|||
|
||||
close(proc.done)
|
||||
|
||||
// Broadcast lifecycle completion.
|
||||
switch status {
|
||||
case StatusKilled:
|
||||
exitAction := ActionProcessExited{
|
||||
ID: id,
|
||||
ExitCode: exitCode,
|
||||
Duration: duration,
|
||||
Error: exitErr,
|
||||
}
|
||||
if status == StatusKilled {
|
||||
exitAction.Error = coreerr.E("Service.StartWithOptions", "process was killed", nil)
|
||||
_ = s.Core().ACTION(ActionProcessKilled{
|
||||
ID: id,
|
||||
Signal: signalName,
|
||||
})
|
||||
default:
|
||||
_ = s.Core().ACTION(ActionProcessExited{
|
||||
ID: id,
|
||||
ExitCode: exitCode,
|
||||
Duration: duration,
|
||||
Error: exitErr,
|
||||
})
|
||||
}
|
||||
|
||||
_ = s.Core().ACTION(exitAction)
|
||||
}()
|
||||
|
||||
return proc, nil
|
||||
|
|
|
|||
|
|
@ -248,6 +248,7 @@ func TestService_Actions(t *testing.T) {
|
|||
svc := raw.(*Service)
|
||||
|
||||
var killed []ActionProcessKilled
|
||||
var exited []ActionProcessExited
|
||||
var mu sync.Mutex
|
||||
|
||||
c.RegisterAction(func(cc *framework.Core, msg framework.Message) framework.Result {
|
||||
|
|
@ -256,6 +257,9 @@ func TestService_Actions(t *testing.T) {
|
|||
if m, ok := msg.(ActionProcessKilled); ok {
|
||||
killed = append(killed, m)
|
||||
}
|
||||
if m, ok := msg.(ActionProcessExited); ok {
|
||||
exited = append(exited, m)
|
||||
}
|
||||
return framework.Result{OK: true}
|
||||
})
|
||||
|
||||
|
|
@ -278,8 +282,43 @@ func TestService_Actions(t *testing.T) {
|
|||
assert.Len(t, killed, 1)
|
||||
assert.Equal(t, proc.ID, killed[0].ID)
|
||||
assert.NotEmpty(t, killed[0].Signal)
|
||||
assert.Len(t, exited, 1)
|
||||
assert.Equal(t, proc.ID, exited[0].ID)
|
||||
assert.Error(t, exited[0].Error)
|
||||
assert.Equal(t, StatusKilled, proc.Status)
|
||||
})
|
||||
|
||||
t.Run("broadcasts exited event on start failure", 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}
|
||||
})
|
||||
|
||||
_, err = svc.Start(context.Background(), "definitely-not-a-real-binary-xyz")
|
||||
require.Error(t, err)
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
require.Len(t, exited, 1)
|
||||
assert.Equal(t, -1, exited[0].ExitCode)
|
||||
assert.Error(t, exited[0].Error)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_List(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue