diff options
author | Valery Piashchynski <[email protected]> | 2022-05-31 13:56:34 +0200 |
---|---|---|
committer | Valery Piashchynski <[email protected]> | 2022-05-31 13:56:34 +0200 |
commit | 467e427bf67bffe3dd0df41842dad797b93f56f9 (patch) | |
tree | 4c2fb253c753738674f9df73e1e4426d6b4a9b5f | |
parent | d35e5087b0dd4be258d78587ead9e12baf89c760 (diff) |
feat: `rr stop` command
Signed-off-by: Valery Piashchynski <[email protected]>
-rw-r--r-- | .pid | 1 | ||||
-rw-r--r-- | internal/cli/root.go | 64 | ||||
-rw-r--r-- | internal/cli/serve/command.go | 2 | ||||
-rw-r--r-- | internal/cli/stop/command.go | 53 | ||||
-rw-r--r-- | internal/cli/stop/command_test.go | 27 |
5 files changed, 126 insertions, 21 deletions
@@ -0,0 +1 @@ +100144
\ No newline at end of file diff --git a/internal/cli/root.go b/internal/cli/root.go index 50f93795..0ea12814 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -5,10 +5,12 @@ import ( "os" "path/filepath" "runtime" + "strconv" "github.com/roadrunner-server/errors" "github.com/roadrunner-server/roadrunner/v2/internal/cli/reset" "github.com/roadrunner-server/roadrunner/v2/internal/cli/serve" + "github.com/roadrunner-server/roadrunner/v2/internal/cli/stop" "github.com/roadrunner-server/roadrunner/v2/internal/cli/workers" dbg "github.com/roadrunner-server/roadrunner/v2/internal/debug" "github.com/roadrunner-server/roadrunner/v2/internal/meta" @@ -17,21 +19,29 @@ import ( "github.com/spf13/cobra" ) -// NewCommand creates root command. -func NewCommand(cmdName string) *cobra.Command { //nolint:funlen - const ( - envDotenv string = "DOTENV_PATH" // env var name: path to the .env file - ) +const ( + // env var name: path to the .env file + envDotenv string = "DOTENV_PATH" + pidFileName string = ".pid" +) - var ( // flag values - cfgFile = strPtr("") // path to the .rr.yaml - workDir string // working directory - dotenv string // path to the .env file - debug bool // debug mode - override = &[]string{} // override config values - // do not print startup message - silent = boolPtr(false) - ) +// NewCommand creates root command. +func NewCommand(cmdName string) *cobra.Command { //nolint:funlen,gocognit + // path to the .rr.yaml + cfgFile := toPtr("") + // pidfile path + pidFile := toPtr(false) + // override config values + override := &[]string{} + // do not print startup message + silent := toPtr(false) + + // working directory + var workDir string + // path to the .env file + var dotenv string + // debug mode + var debug bool cmd := &cobra.Command{ Use: cmdName, @@ -81,12 +91,29 @@ func NewCommand(cmdName string) *cobra.Command { //nolint:funlen go func() { _ = srv.Start(":6061") }() // TODO implement graceful server stopping } + // user wanted to write a .pid file + if *pidFile { + f, err := os.Create(pidFileName) + if err != nil { + return err + } + defer func() { + _ = f.Close() + }() + + _, err = f.WriteString(strconv.Itoa(os.Getpid())) + if err != nil { + return err + } + } + return nil }, } f := cmd.PersistentFlags() + f.BoolVarP(pidFile, "pid", "p", false, "create a .pid file") f.StringVarP(cfgFile, "config", "c", ".rr.yaml", "config file") f.StringVarP(&workDir, "WorkDir", "w", "", "working directory") f.StringVarP(&dotenv, "dotenv", "", "", fmt.Sprintf("dotenv file [$%s]", envDotenv)) @@ -98,15 +125,12 @@ func NewCommand(cmdName string) *cobra.Command { //nolint:funlen workers.NewCommand(cfgFile, override), reset.NewCommand(cfgFile, override, silent), serve.NewCommand(override, cfgFile, silent), + stop.NewCommand(silent), ) return cmd } -func strPtr(s string) *string { - return &s -} - -func boolPtr(b bool) *bool { - return &b +func toPtr[T any](val T) *T { + return &val } diff --git a/internal/cli/serve/command.go b/internal/cli/serve/command.go index 3a1e945c..6cbdef44 100644 --- a/internal/cli/serve/command.go +++ b/internal/cli/serve/command.go @@ -98,7 +98,7 @@ func NewCommand(override *[]string, cfgFile *string, silent *bool) *cobra.Comman case e := <-errCh: return fmt.Errorf("error: %w\nplugin: %s", e.Error, e.VertexID) case <-stop: // stop the container after first signal - fmt.Printf("stop signal received, grace timeout is: %f seconds\n", containerCfg.GracePeriod.Seconds()) + fmt.Printf("stop signal received, grace timeout is: %0.f seconds\n", containerCfg.GracePeriod.Seconds()) if err = endureContainer.Stop(); err != nil { return fmt.Errorf("error: %w", err) diff --git a/internal/cli/stop/command.go b/internal/cli/stop/command.go new file mode 100644 index 00000000..8b4b589f --- /dev/null +++ b/internal/cli/stop/command.go @@ -0,0 +1,53 @@ +package stop + +import ( + "log" + "os" + "strconv" + "syscall" + + "github.com/roadrunner-server/errors" + "github.com/spf13/cobra" +) + +const ( + // sync with root.go + pidFileName string = ".pid" +) + +// NewCommand creates `serve` command. +func NewCommand(silent *bool) *cobra.Command { + return &cobra.Command{ + Use: "stop", + Short: "Stop RoadRunner server", + RunE: func(*cobra.Command, []string) error { + const op = errors.Op("rr_stop") + + data, err := os.ReadFile(pidFileName) + if err != nil { + return errors.Errorf("%v, to create a .pid file, you must run RR with the following options: './rr serve -p'", err) + } + + pid, err := strconv.Atoi(string(data)) + if err != nil { + return errors.E(op, err) + } + + process, err := os.FindProcess(pid) + if err != nil { + return errors.E(op, err) + } + + if !*silent { + log.Printf("stopping process with PID: %d", pid) + } + + err = process.Signal(syscall.SIGTERM) + if err != nil { + return errors.E(op, err) + } + + return nil + }, + } +} diff --git a/internal/cli/stop/command_test.go b/internal/cli/stop/command_test.go new file mode 100644 index 00000000..8bbb29ea --- /dev/null +++ b/internal/cli/stop/command_test.go @@ -0,0 +1,27 @@ +package stop_test + +import ( + "testing" + + "github.com/roadrunner-server/roadrunner/v2/internal/cli/stop" + + "github.com/stretchr/testify/assert" +) + +func TestCommandProperties(t *testing.T) { + cmd := stop.NewCommand(toPtr(false)) + + assert.Equal(t, "stop", cmd.Use) + assert.NotNil(t, cmd.RunE) +} + +func TestCommandTrue(t *testing.T) { + cmd := stop.NewCommand(toPtr(true)) + + assert.Equal(t, "stop", cmd.Use) + assert.NotNil(t, cmd.RunE) +} + +func toPtr[T any](val T) *T { + return &val +} |