Add PID-based process kill support
This commit is contained in:
parent
ce2a4db6cb
commit
24f853631d
5 changed files with 70 additions and 0 deletions
|
|
@ -23,6 +23,14 @@ type TaskProcessRun struct {
|
|||
KillGroup bool
|
||||
}
|
||||
|
||||
// TaskProcessKill requests termination of a managed process by ID or PID.
|
||||
type TaskProcessKill struct {
|
||||
// ID identifies a managed process started by this service.
|
||||
ID string
|
||||
// PID targets a process directly when ID is not available.
|
||||
PID int
|
||||
}
|
||||
|
||||
// ActionProcessStarted is broadcast when a process begins execution.
|
||||
type ActionProcessStarted struct {
|
||||
ID string
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ func TestGlobal_DefaultNotInitialized(t *testing.T) {
|
|||
err = Kill("proc-1")
|
||||
assert.ErrorIs(t, err, ErrServiceNotInitialized)
|
||||
|
||||
err = KillPID(1234)
|
||||
assert.ErrorIs(t, err, ErrServiceNotInitialized)
|
||||
|
||||
_, err = StartWithOptions(context.Background(), RunOptions{Command: "echo"})
|
||||
assert.ErrorIs(t, err, ErrServiceNotInitialized)
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,15 @@ func Kill(id string) error {
|
|||
return svc.Kill(id)
|
||||
}
|
||||
|
||||
// KillPID terminates a process by operating-system PID using the default service.
|
||||
func KillPID(pid int) error {
|
||||
svc := Default()
|
||||
if svc == nil {
|
||||
return ErrServiceNotInitialized
|
||||
}
|
||||
return svc.KillPID(pid)
|
||||
}
|
||||
|
||||
// StartWithOptions spawns a process with full configuration using the default service.
|
||||
func StartWithOptions(ctx context.Context, opts RunOptions) (*Process, error) {
|
||||
svc := Default()
|
||||
|
|
|
|||
28
service.go
28
service.go
|
|
@ -338,6 +338,19 @@ func (s *Service) Kill(id string) error {
|
|||
return proc.Kill()
|
||||
}
|
||||
|
||||
// KillPID terminates a process by operating-system PID.
|
||||
func (s *Service) KillPID(pid int) error {
|
||||
if pid <= 0 {
|
||||
return coreerr.E("Service.KillPID", "pid must be positive", nil)
|
||||
}
|
||||
|
||||
if err := syscall.Kill(pid, syscall.SIGTERM); err != nil {
|
||||
return coreerr.E("Service.KillPID", fmt.Sprintf("failed to signal pid %d", pid), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes a completed process from the list.
|
||||
func (s *Service) Remove(id string) error {
|
||||
s.mu.Lock()
|
||||
|
|
@ -435,6 +448,21 @@ func (s *Service) handleTask(c *core.Core, task core.Task) core.Result {
|
|||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
return core.Result{Value: output, OK: true}
|
||||
case TaskProcessKill:
|
||||
switch {
|
||||
case m.ID != "":
|
||||
if err := s.Kill(m.ID); err != nil {
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
return core.Result{OK: true}
|
||||
case m.PID > 0:
|
||||
if err := s.KillPID(m.PID); err != nil {
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
return core.Result{OK: true}
|
||||
default:
|
||||
return core.Result{Value: coreerr.E("Service.handleTask", "task process kill requires an id or pid", nil), OK: false}
|
||||
}
|
||||
default:
|
||||
return core.Result{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -525,6 +525,28 @@ func TestService_OnStartup(t *testing.T) {
|
|||
require.False(t, result.OK)
|
||||
assert.Nil(t, result.Value)
|
||||
})
|
||||
|
||||
t.Run("registers process.kill task", func(t *testing.T) {
|
||||
svc, c := newTestService(t)
|
||||
|
||||
err := svc.OnStartup(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
proc, err := svc.Start(context.Background(), "sleep", "60")
|
||||
require.NoError(t, err)
|
||||
require.True(t, proc.IsRunning())
|
||||
|
||||
result := c.PERFORM(TaskProcessKill{PID: proc.Info().PID})
|
||||
require.True(t, result.OK)
|
||||
|
||||
select {
|
||||
case <-proc.Done():
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("process should have been killed by pid")
|
||||
}
|
||||
|
||||
assert.Equal(t, StatusKilled, proc.Status)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_RunWithOptions(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue