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 (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -33,11 +34,12 @@ func (m *markerResponse) WriteHeader(statusCode int) {
|
||||
}
|
||||
|
||||
type binHandler struct {
|
||||
command string
|
||||
workDir string
|
||||
shell string
|
||||
environment []string
|
||||
timeout time.Duration
|
||||
command string
|
||||
workDir string
|
||||
shell string
|
||||
environment []string
|
||||
timeout time.Duration
|
||||
gracefulTimeout time.Duration
|
||||
}
|
||||
|
||||
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.Env = env
|
||||
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()
|
||||
done = true
|
||||
|
||||
if codeReset, ok := writer.(interface{ Status(status int) }); ok && err != nil {
|
||||
codeReset.Status(http.StatusBadGateway)
|
||||
|
File diff suppressed because one or more lines are too long
@ -26,17 +26,18 @@ import (
|
||||
)
|
||||
|
||||
type Unit struct {
|
||||
Interval time.Duration `yaml:"interval,omitempty"` // interval between attempts
|
||||
Attempts int `yaml:"attempts,omitempty"` // maximum number of attempts
|
||||
Workers int `yaml:"workers,omitempty"` // concurrency level - number of parallel requests
|
||||
Mode string `yaml:"mode,omitempty"` // execution mode: bin, cgi or proxy
|
||||
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
|
||||
Timeout time.Duration `yaml:"timeout,omitempty"` // maximum execution timeout (enabled only for bin mode and only if positive)
|
||||
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)
|
||||
MaxRequest int64 `yaml:"max_request,omitempty"` // optional maximum HTTP body size (enabled if positive)
|
||||
Authorization struct {
|
||||
Interval time.Duration `yaml:"interval,omitempty"` // interval between attempts
|
||||
Attempts int `yaml:"attempts,omitempty"` // maximum number of attempts
|
||||
Workers int `yaml:"workers,omitempty"` // concurrency level - number of parallel requests
|
||||
Mode string `yaml:"mode,omitempty"` // execution mode: bin, cgi or proxy
|
||||
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
|
||||
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)
|
||||
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)
|
||||
Authorization struct {
|
||||
JWT struct {
|
||||
Enable bool `yaml:"enable"` // enable JWT verification
|
||||
JWT `yaml:",inline"`
|
||||
@ -242,11 +243,12 @@ func (cfg Unit) createRunner() (http.Handler, error) {
|
||||
switch cfg.Mode {
|
||||
case "bin":
|
||||
return &binHandler{
|
||||
command: cfg.Command,
|
||||
workDir: cfg.WorkDir,
|
||||
shell: cfg.Shell,
|
||||
timeout: cfg.Timeout,
|
||||
environment: append(os.Environ(), makeEnvList(cfg.Environment)...),
|
||||
command: cfg.Command,
|
||||
workDir: cfg.WorkDir,
|
||||
shell: cfg.Shell,
|
||||
timeout: cfg.Timeout,
|
||||
gracefulTimeout: cfg.GracefulTimeout,
|
||||
environment: append(os.Environ(), makeEnvList(cfg.Environment)...),
|
||||
}, nil
|
||||
case "cgi":
|
||||
return &cgi.Handler{
|
||||
|
@ -50,14 +50,25 @@
|
||||
<dd class="col-sm-9">{{.Unit.Attempts}}</dd>
|
||||
<dt class="col-sm-3">Interval</dt>
|
||||
<dd class="col-sm-9">{{.Unit.Interval}}</dd>
|
||||
<dt class="col-sm-3">Timeout</dt>
|
||||
<dd class="col-sm-9">
|
||||
{{with .Unit.Timeout}}
|
||||
{{.}}
|
||||
{{else}}
|
||||
∞
|
||||
{{end}}
|
||||
</dd>
|
||||
{{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">
|
||||
{{with .Unit.Timeout}}
|
||||
{{.}}
|
||||
{{else}}
|
||||
∞
|
||||
{{end}}
|
||||
</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>
|
||||
<dd class="col-sm-9">
|
||||
{{with .Unit.MaxRequest}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user