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:
stffabi 2020-11-01 11:43:36 +01:00
parent fe2ca14452
commit 7cc3fb296c

View File

@ -7,6 +7,8 @@ import (
"fmt"
"os"
"path/filepath"
"syscall"
"time"
"github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
@ -15,7 +17,7 @@ import (
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])
flags := flag.NewFlagSet(command, flag.ExitOnError)
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")
for _, cFlag := range cFlags {
cFlag(flags)
}
if err := flags.Parse(args); err != nil {
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) {
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)
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 {
log.WithError(err).Fatal(msg)
}
@ -99,7 +108,7 @@ func (c *logio) Close() error {
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)
runtimeConfig := getRuntimeConfig(path)
@ -126,16 +135,37 @@ func stop(ctx context.Context, service, sock, basePath string) (string, uint32,
id := ctr.ID()
pid := task.Pid()
err = task.Kill(ctx, 9)
err = task.Kill(ctx, syscall.SIGTERM)
if err != nil {
return "", 0, "killing task", err
return "", 0, "sopping task", err
}
_, err = task.Wait(ctx)
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 {
return "", 0, "killing task", err
}
s, err = task.Wait(ctx)
if err != nil {
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)
if err != nil {
return "", 0, "deleting task", err