mirror of
https://github.com/F1bonacc1/process-compose.git
synced 2024-10-03 22:27:13 +03:00
support configurable termination parameters
This commit is contained in:
parent
d1b9777230
commit
abf1145d46
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
coverage.out
|
||||
.vscode
|
||||
bin/**
|
||||
bin/process*
|
||||
*.log
|
||||
.env
|
||||
# local build output via go build
|
||||
|
25
README.md
25
README.md
@ -149,12 +149,33 @@ process2:
|
||||
```yaml
|
||||
process2:
|
||||
depends_on:
|
||||
process2:
|
||||
condition: process_completed_successfully # or "process_started" (default)
|
||||
process3:
|
||||
condition: process_completed_successfully # or "process_started" (default)
|
||||
process3:
|
||||
condition: process_completed_successfully
|
||||
```
|
||||
|
||||
##### ✅ Termination Parameters
|
||||
|
||||
```yaml
|
||||
process1:
|
||||
command: "pg_ctl start"
|
||||
shutdown:
|
||||
command: "pg_ctl stop"
|
||||
timeout_seconds: 10 # default 10
|
||||
signal: 15 # default 15, but only if command is not defined or empty
|
||||
```
|
||||
|
||||
`shutdown` is optional and can be omitted. The default behaviour in this case: `SIGTERM` is issued to the running process.
|
||||
|
||||
In case only `shutdown.signal` is defined `[1..31] ` the running process will be terminated with its value.
|
||||
|
||||
In case the the `shutdown.command` is defined:
|
||||
|
||||
1. The `shutdown.command` is executed with all the Environment Variables of the main process
|
||||
2. Wait `shutdown.timeout_seconds` for its completion (if not defined wait for 10 seconds)
|
||||
3. In case of timeout the process will receive the `SIGKILL` signal
|
||||
|
||||
#### ✅ <u>Output Handling</u>
|
||||
|
||||
##### ✅ Show process name
|
||||
|
0
bin/.gitkeep
Normal file
0
bin/.gitkeep
Normal file
@ -11,7 +11,7 @@ processes:
|
||||
restart: "on-failure"
|
||||
backoff_seconds: 2
|
||||
depends_on:
|
||||
process2:
|
||||
_process2:
|
||||
condition: process_completed_successfully
|
||||
process3:
|
||||
condition: process_completed
|
||||
@ -20,7 +20,7 @@ processes:
|
||||
environment:
|
||||
- 'EXIT_CODE=0'
|
||||
|
||||
process2:
|
||||
_process2:
|
||||
command: "./test_loop.bash process2"
|
||||
log_location: ./pc.proc2.log
|
||||
availability:
|
||||
@ -31,7 +31,11 @@ processes:
|
||||
environment:
|
||||
- 'ABC=2221'
|
||||
- 'PRINT_ERR=111'
|
||||
- 'EXIT_CODE=0'
|
||||
- 'EXIT_CODE=2'
|
||||
shutdown:
|
||||
command: "pkill -f process2"
|
||||
signal: 15
|
||||
timeout_seconds: 2
|
||||
|
||||
process3:
|
||||
command: "./test_loop.bash process3"
|
||||
@ -48,7 +52,7 @@ processes:
|
||||
# restart: on-failure
|
||||
environment:
|
||||
- 'ABC=2221'
|
||||
- 'EXIT_CODE=1'
|
||||
- 'EXIT_CODE=4'
|
||||
|
||||
kcalc:
|
||||
command: "kcalc"
|
||||
|
@ -24,14 +24,15 @@ type Project struct {
|
||||
|
||||
type Processes map[string]ProcessConfig
|
||||
type ProcessConfig struct {
|
||||
Name string
|
||||
Disabled bool `yaml:"disabled,omitempty"`
|
||||
Command string `yaml:"command"`
|
||||
LogLocation string `yaml:"log_location,omitempty"`
|
||||
Environment []string `yaml:"environment,omitempty"`
|
||||
RestartPolicy RestartPolicyConfig `yaml:"availability,omitempty"`
|
||||
DependsOn DependsOnConfig `yaml:"depends_on,omitempty"`
|
||||
Extensions map[string]interface{} `yaml:",inline"`
|
||||
Name string
|
||||
Disabled bool `yaml:"disabled,omitempty"`
|
||||
Command string `yaml:"command"`
|
||||
LogLocation string `yaml:"log_location,omitempty"`
|
||||
Environment []string `yaml:"environment,omitempty"`
|
||||
RestartPolicy RestartPolicyConfig `yaml:"availability,omitempty"`
|
||||
DependsOn DependsOnConfig `yaml:"depends_on,omitempty"`
|
||||
ShutDownParams ShutDownParams `yaml:"shutdown,omitempty"`
|
||||
Extensions map[string]interface{} `yaml:",inline"`
|
||||
}
|
||||
|
||||
type ProcessState struct {
|
||||
@ -74,6 +75,12 @@ type RestartPolicyConfig struct {
|
||||
MaxRestarts int `yaml:"max_restarts,omitempty"`
|
||||
}
|
||||
|
||||
type ShutDownParams struct {
|
||||
ShutDownCommand string `yaml:"command,omitempty"`
|
||||
ShutDownTimeout int `yaml:"timeout_seconds,omitempty"`
|
||||
Signal int `yaml:"signal,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
// ProcessConditionCompleted is the type for waiting until a process has completed (any exit code).
|
||||
ProcessConditionCompleted = "process_completed"
|
||||
|
@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
@ -10,6 +11,7 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/f1bonacc1/process-compose/src/pclog"
|
||||
@ -18,6 +20,10 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
DEFAULT_SHUTDOWN_TIMEOUT_SEC = 10
|
||||
)
|
||||
|
||||
type Process struct {
|
||||
globalEnv []string
|
||||
procConf ProcessConfig
|
||||
@ -156,6 +162,33 @@ func (p *Process) WontRun() {
|
||||
|
||||
}
|
||||
|
||||
func (p *Process) shutDown() error {
|
||||
if isStringDefined(p.procConf.ShutDownParams.ShutDownCommand) {
|
||||
return p.doConfiguredStop(p.procConf.ShutDownParams)
|
||||
}
|
||||
return p.stop(p.procConf.ShutDownParams.Signal)
|
||||
}
|
||||
|
||||
func (p *Process) doConfiguredStop(params ShutDownParams) error {
|
||||
timeout := params.ShutDownTimeout
|
||||
if timeout == 0 {
|
||||
timeout = DEFAULT_SHUTDOWN_TIMEOUT_SEC
|
||||
}
|
||||
log.Debug().Msgf("killing %s with timeout %d ...", p.GetName(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, getRunnerShell(), getRunnerArg(), params.ShutDownCommand)
|
||||
cmd.Env = p.getProcessEnvironment()
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
// the process termination timedout and it will be killed
|
||||
log.Error().Msgf("killing %s with timeout %d failed", p.GetName(), timeout)
|
||||
return p.stop(int(syscall.SIGKILL))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Process) onProcessEnd() {
|
||||
if isStringDefined(p.procConf.LogLocation) {
|
||||
p.logger.Close()
|
||||
|
@ -2,12 +2,22 @@
|
||||
|
||||
package app
|
||||
|
||||
import "syscall"
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (p *Process) stop() error {
|
||||
const (
|
||||
min_sig = 1
|
||||
max_sig = 31
|
||||
)
|
||||
|
||||
func (p *Process) stop(sig int) error {
|
||||
if sig < min_sig || sig > max_sig {
|
||||
sig = int(syscall.SIGTERM)
|
||||
}
|
||||
pgid, err := syscall.Getpgid(p.cmd.Process.Pid)
|
||||
if err == nil {
|
||||
return syscall.Kill(-pgid, syscall.SIGKILL)
|
||||
return syscall.Kill(-pgid, syscall.Signal(sig))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (p *Process) stop() error {
|
||||
func (p *Process) stop(sig int) error {
|
||||
//p.cmd.Process.Kill()
|
||||
kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(p.cmd.Process.Pid))
|
||||
return kill.Run()
|
||||
|
@ -182,7 +182,7 @@ func (p *Project) StopProcess(name string) error {
|
||||
log.Error().Msgf("Process %s is not running", name)
|
||||
return fmt.Errorf("process %s is not running", name)
|
||||
}
|
||||
proc.stop()
|
||||
proc.shutDown()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
#trap "echo ERROR: The program is terminated ; exit" SIGTERM
|
||||
trap 'echo CODE: $?; exit $EXIT_CODE' 1 2 3 15
|
||||
|
||||
LOOPS=30000
|
||||
for (( i=1; i<=LOOPS; i++ ))
|
||||
do
|
||||
sleep 0.01
|
||||
#sleep 0.01
|
||||
sleep 0.5
|
||||
|
||||
if [[ -z "${PRINT_ERR}" ]]; then
|
||||
echo "test loop $i loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop loop $1 $ABC"
|
||||
|
Loading…
Reference in New Issue
Block a user