add graceful shutdown for bin mode
This commit is contained in:
parent
a183d116a1
commit
6d3d90b0e2
18
_docs/modes.md
Normal file
18
_docs/modes.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
## BIN
|
||||||
|
|
||||||
|
Binary modes just executes any script in shell (`/bin/sh` by default). You can override shell per-unit
|
||||||
|
by `shell: /path/to/shell` configuration param.
|
||||||
|
|
||||||
|
To handle a graceful timeout, child should be able to forward signal: basically, use `exec` before last command.
|
||||||
|
|
||||||
|
Danger (but will work), signals may not be handled by foo
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
command: "V=1 RAIL=2 foo bar -c -y -z"
|
||||||
|
```
|
||||||
|
|
||||||
|
Good
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
command: "V=1 RAIL=2 exec foo bar -c -y -z"
|
||||||
|
```
|
@ -3,6 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -38,6 +39,7 @@ type binHandler struct {
|
|||||||
shell string
|
shell string
|
||||||
environment []string
|
environment []string
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
gracefulTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bh *binHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
func (bh *binHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||||
@ -75,7 +77,29 @@ func (bh *binHandler) ServeHTTP(writer http.ResponseWriter, request *http.Reques
|
|||||||
cmd.Stdout = marker
|
cmd.Stdout = marker
|
||||||
cmd.Env = env
|
cmd.Env = env
|
||||||
api.SetBinFlags(cmd)
|
api.SetBinFlags(cmd)
|
||||||
|
|
||||||
|
var done bool
|
||||||
|
|
||||||
|
if bh.gracefulTimeout > 0 {
|
||||||
|
graceCtx, graceCancel := context.WithTimeout(ctx, bh.gracefulTimeout)
|
||||||
|
defer graceCancel()
|
||||||
|
go func() {
|
||||||
|
<-graceCtx.Done()
|
||||||
|
proc := cmd.Process
|
||||||
|
if proc == nil || done {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := proc.Signal(os.Interrupt)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("failed send signal to process:", err)
|
||||||
|
} else {
|
||||||
|
log.Println("sent graceful shutdown to proces")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
|
done = true
|
||||||
|
|
||||||
if codeReset, ok := writer.(interface{ Status(status int) }); ok && err != nil {
|
if codeReset, ok := writer.(interface{ Status(status int) }); ok && err != nil {
|
||||||
codeReset.Status(http.StatusBadGateway)
|
codeReset.Status(http.StatusBadGateway)
|
||||||
|
File diff suppressed because one or more lines are too long
@ -33,6 +33,7 @@ type Unit struct {
|
|||||||
WorkDir string `yaml:"workdir,omitempty"` // working directory for the worker. if empty - temporary one will generated automatically
|
WorkDir string `yaml:"workdir,omitempty"` // working directory for the worker. if empty - temporary one will generated automatically
|
||||||
Command string `yaml:"command"` // command in a shell to execute
|
Command string `yaml:"command"` // command in a shell to execute
|
||||||
Timeout time.Duration `yaml:"timeout,omitempty"` // maximum execution timeout (enabled only for bin mode and only if positive)
|
Timeout time.Duration `yaml:"timeout,omitempty"` // maximum execution timeout (enabled only for bin mode and only if positive)
|
||||||
|
GracefulTimeout time.Duration `yaml:"graceful_timeout,omitempty"` // maximum execution timeout after which SIGINT will be sent (enabled only for bin mode and only if positive)
|
||||||
Shell string `yaml:"shell,omitempty"` // shell to execute command in bin mode (default - /bin/sh)
|
Shell string `yaml:"shell,omitempty"` // shell to execute command in bin mode (default - /bin/sh)
|
||||||
Environment map[string]string `yaml:"environment,omitempty"` // custom environment for executable (in addition to system)
|
Environment map[string]string `yaml:"environment,omitempty"` // custom environment for executable (in addition to system)
|
||||||
MaxRequest int64 `yaml:"max_request,omitempty"` // optional maximum HTTP body size (enabled if positive)
|
MaxRequest int64 `yaml:"max_request,omitempty"` // optional maximum HTTP body size (enabled if positive)
|
||||||
@ -246,6 +247,7 @@ func (cfg Unit) createRunner() (http.Handler, error) {
|
|||||||
workDir: cfg.WorkDir,
|
workDir: cfg.WorkDir,
|
||||||
shell: cfg.Shell,
|
shell: cfg.Shell,
|
||||||
timeout: cfg.Timeout,
|
timeout: cfg.Timeout,
|
||||||
|
gracefulTimeout: cfg.GracefulTimeout,
|
||||||
environment: append(os.Environ(), makeEnvList(cfg.Environment)...),
|
environment: append(os.Environ(), makeEnvList(cfg.Environment)...),
|
||||||
}, nil
|
}, nil
|
||||||
case "cgi":
|
case "cgi":
|
||||||
|
@ -50,7 +50,8 @@
|
|||||||
<dd class="col-sm-9">{{.Unit.Attempts}}</dd>
|
<dd class="col-sm-9">{{.Unit.Attempts}}</dd>
|
||||||
<dt class="col-sm-3">Interval</dt>
|
<dt class="col-sm-3">Interval</dt>
|
||||||
<dd class="col-sm-9">{{.Unit.Interval}}</dd>
|
<dd class="col-sm-9">{{.Unit.Interval}}</dd>
|
||||||
<dt class="col-sm-3">Timeout</dt>
|
{{if eq .Unit.Mode "bin"}}
|
||||||
|
<dt class="col-sm-3" title="Timeout after which process will be sent">Timeout</dt>
|
||||||
<dd class="col-sm-9">
|
<dd class="col-sm-9">
|
||||||
{{with .Unit.Timeout}}
|
{{with .Unit.Timeout}}
|
||||||
{{.}}
|
{{.}}
|
||||||
@ -58,6 +59,16 @@
|
|||||||
∞
|
∞
|
||||||
{{end}}
|
{{end}}
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt class="col-sm-3" title="Timeout after which SIGINT will be sent">Graceful timeout
|
||||||
|
</dt>
|
||||||
|
<dd class="col-sm-9">
|
||||||
|
{{with .Unit.GracefulTimeout}}
|
||||||
|
{{.}}
|
||||||
|
{{else}}
|
||||||
|
∞
|
||||||
|
{{end}}
|
||||||
|
</dd>
|
||||||
|
{{end}}
|
||||||
<dt class="col-sm-3">Max request size</dt>
|
<dt class="col-sm-3">Max request size</dt>
|
||||||
<dd class="col-sm-9">
|
<dd class="col-sm-9">
|
||||||
{{with .Unit.MaxRequest}}
|
{{with .Unit.MaxRequest}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user