mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 09:16:29 +00:00
Gracefully stop a service with service stop
First send a SIGTERM to the service task and wait for it to be stopped. If it doesn’t stop in the time specified, a SIGKILL will be send to the task. Signed-off-by: stffabi <stffabi@users.noreply.github.com>
This commit is contained in:
parent
fe2ca14452
commit
7cc3fb296c
@ -7,6 +7,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/cio"
|
"github.com/containerd/containerd/cio"
|
||||||
@ -15,7 +17,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseCmd(ctx context.Context, command string, args []string) (*log.Entry, string, string, string, string) {
|
func parseCmd(ctx context.Context, command string, args []string, cFlags ...func(*flag.FlagSet)) (*log.Entry, string, string, string, string) {
|
||||||
invoked := filepath.Base(os.Args[0])
|
invoked := filepath.Base(os.Args[0])
|
||||||
flags := flag.NewFlagSet(command, flag.ExitOnError)
|
flags := flag.NewFlagSet(command, flag.ExitOnError)
|
||||||
flags.Usage = func() {
|
flags.Usage = func() {
|
||||||
@ -29,6 +31,10 @@ func parseCmd(ctx context.Context, command string, args []string) (*log.Entry, s
|
|||||||
|
|
||||||
dumpSpec := flags.String("dump-spec", "", "Dump container spec to file before start")
|
dumpSpec := flags.String("dump-spec", "", "Dump container spec to file before start")
|
||||||
|
|
||||||
|
for _, cFlag := range cFlags {
|
||||||
|
cFlag(flags)
|
||||||
|
}
|
||||||
|
|
||||||
if err := flags.Parse(args); err != nil {
|
if err := flags.Parse(args); err != nil {
|
||||||
log.Fatal("Unable to parse args")
|
log.Fatal("Unable to parse args")
|
||||||
}
|
}
|
||||||
@ -50,10 +56,13 @@ func parseCmd(ctx context.Context, command string, args []string) (*log.Entry, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func stopCmd(ctx context.Context, args []string) {
|
func stopCmd(ctx context.Context, args []string) {
|
||||||
log, service, sock, path, _ := parseCmd(ctx, "stop", args)
|
timeout := 10
|
||||||
|
log, service, sock, path, _ := parseCmd(ctx, "stop", args, func(flags *flag.FlagSet) {
|
||||||
|
flags.IntVar(&timeout, "time", 10, "Seconds to wait for stop before killing the service")
|
||||||
|
})
|
||||||
|
|
||||||
log.Infof("Stopping service: %q", service)
|
log.Infof("Stopping service: %q", service)
|
||||||
id, pid, msg, err := stop(ctx, service, sock, path)
|
id, pid, msg, err := stop(ctx, service, sock, path, time.Duration(timeout)*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Fatal(msg)
|
log.WithError(err).Fatal(msg)
|
||||||
}
|
}
|
||||||
@ -99,7 +108,7 @@ func (c *logio) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop(ctx context.Context, service, sock, basePath string) (string, uint32, string, error) {
|
func stop(ctx context.Context, service, sock, basePath string, timeBeforeKill time.Duration) (string, uint32, string, error) {
|
||||||
path := filepath.Join(basePath, service)
|
path := filepath.Join(basePath, service)
|
||||||
|
|
||||||
runtimeConfig := getRuntimeConfig(path)
|
runtimeConfig := getRuntimeConfig(path)
|
||||||
@ -126,16 +135,37 @@ func stop(ctx context.Context, service, sock, basePath string) (string, uint32,
|
|||||||
id := ctr.ID()
|
id := ctr.ID()
|
||||||
pid := task.Pid()
|
pid := task.Pid()
|
||||||
|
|
||||||
err = task.Kill(ctx, 9)
|
err = task.Kill(ctx, syscall.SIGTERM)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, "sopping task", err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, "waiting for task to exit", err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-s:
|
||||||
|
case <-time.After(timeBeforeKill):
|
||||||
|
log.Infof("Task did not stop after timeout, killing it...")
|
||||||
|
err = task.Kill(ctx, syscall.SIGKILL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, "killing task", err
|
return "", 0, "killing task", err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = task.Wait(ctx)
|
s, err = task.Wait(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, "waiting for task to exit", err
|
return "", 0, "waiting for task to exit", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-s:
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
return "", 0, "killed, but did not stop", fmt.Errorf("Timeout waiting")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err = task.Delete(ctx)
|
_, err = task.Delete(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, "deleting task", err
|
return "", 0, "deleting task", err
|
||||||
|
Loading…
Reference in New Issue
Block a user