Add periodic exec of one-shot commands
This commit is contained in:
@@ -13,4 +13,4 @@ func (cnf Config) SetIOPriority(which int, who int, prio uint32) (err error) {
|
||||
return cnf.NotImplementedError
|
||||
}
|
||||
|
||||
func (cnf Config) IORenice(cnf Config, p *proc.Process, processName string) {}
|
||||
func (cnf Config) IORenice(p *proc.Process, processName string) {}
|
||||
|
||||
@@ -3,6 +3,7 @@ package lib
|
||||
import (
|
||||
"log"
|
||||
"math"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -13,100 +14,149 @@ import (
|
||||
|
||||
// reniced основная логика.
|
||||
func (cnf Config) Reniced() {
|
||||
var (
|
||||
processListUpdateTimer *time.Ticker
|
||||
processKillTimer *time.Ticker
|
||||
processReniceTimer *time.Ticker
|
||||
processIONiceTimer *time.Ticker
|
||||
processListTimer *time.Ticker
|
||||
processList []*proc.Process
|
||||
err error
|
||||
)
|
||||
|
||||
// Прежде всего настроим таймеры
|
||||
processListUpdateTimer = time.NewTicker(time.Duration(cnf.ProcessListUpdatePeriod) * time.Millisecond)
|
||||
processReniceTimer = time.NewTicker(time.Duration(cnf.ProcessNicePeriod) * time.Millisecond)
|
||||
processKillTimer = time.NewTicker(time.Duration(cnf.ProcessKillPeriod) * time.Millisecond)
|
||||
processIONiceTimer = time.NewTicker(time.Duration(cnf.ProcessIONicePeriod) * time.Millisecond)
|
||||
processListTimer = time.NewTicker(time.Duration(cnf.PeriodicProcessInvocationPeriod) * time.Millisecond)
|
||||
|
||||
for {
|
||||
processList, err := proc.Processes()
|
||||
select {
|
||||
// Обновляем список процессов.
|
||||
case <-processListUpdateTimer.C:
|
||||
processList, err = proc.Processes()
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to get process list: %s", err)
|
||||
}
|
||||
|
||||
// Не самый эффективный, зато работающий способ - простой перебор массивов.
|
||||
for _, p := range processList {
|
||||
ok := cnf.Pool.TrySubmit(func() {
|
||||
if processName, err := p.Name(); err == nil {
|
||||
// Для каждого процесса извлекаем его текущий priority.
|
||||
if currentPrioLevel, err := syscall.Getpriority(syscall.PRIO_PROCESS, int(p.Pid)); err == nil {
|
||||
if niceLevel := cnf.Renice[processName]; niceLevel != 0 {
|
||||
prioLevel := niceLevel
|
||||
currentNiceLevel := currentPrioLevel
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
// Value of PR = 20 + (-20 to +19) is 0 to 39
|
||||
switch {
|
||||
case niceLevel > 0:
|
||||
prioLevel = 20 - niceLevel
|
||||
case niceLevel < 0:
|
||||
prioLevel = 20 + int(math.Abs(float64(niceLevel)))
|
||||
default:
|
||||
prioLevel = 20
|
||||
}
|
||||
|
||||
currentNiceLevel = 20 - currentPrioLevel
|
||||
}
|
||||
|
||||
if currentPrioLevel != prioLevel {
|
||||
// on Linux Setpriority actually operates niceness value.
|
||||
_ = syscall.Setpriority(syscall.PRIO_PROCESS, int(p.Pid), niceLevel)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to get process list: %s", err)
|
||||
}
|
||||
// Проходим по списку процессов и посылаем сигналы процессам.
|
||||
case <-processKillTimer.C:
|
||||
for _, p := range processList {
|
||||
ok := cnf.Pool.TrySubmit(func() {
|
||||
if processName, err := p.Name(); err == nil {
|
||||
// Посылаем процессу сигналы, если таковые есть в конфиге.
|
||||
if killSignal := cnf.KillSignal[processName]; killSignal != 0 {
|
||||
switch killSignal { //nolint:exhaustive
|
||||
case syscall.SIGSTOP:
|
||||
_ = p.SendSignal(killSignal)
|
||||
|
||||
if cnf.Debug {
|
||||
log.Printf(
|
||||
"Set niceness for %s(%d) to %d (was %d)",
|
||||
"Matching processName with killProcessname %s(%d), SIG%s sent",
|
||||
processName,
|
||||
p.Pid,
|
||||
strings.ToUpper(killSignal.String()),
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
_ = p.SendSignal(killSignal)
|
||||
|
||||
if cnf.Debug {
|
||||
log.Printf(
|
||||
"Matching processName with killProcessname %s(%d), SIG%s sent",
|
||||
processName,
|
||||
p.Pid,
|
||||
strings.ToUpper(killSignal.String()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if !ok {
|
||||
log.Printf("Unable to add task to pool. Increase nb_capacity?")
|
||||
}
|
||||
}
|
||||
// Проходим по списку процессов и меняем ionice процессам.
|
||||
case <-processIONiceTimer.C:
|
||||
for _, p := range processList {
|
||||
ok := cnf.Pool.TrySubmit(func() {
|
||||
if processName, err := p.Name(); err == nil {
|
||||
cnf.IORenice(p, processName)
|
||||
}
|
||||
})
|
||||
|
||||
if !ok {
|
||||
log.Printf("Unable to add task to pool. Increase nb_capacity?")
|
||||
}
|
||||
}
|
||||
// Проходим по списку того, что надо запустить и запускаем.
|
||||
case <-processListTimer.C:
|
||||
for _, v := range cnf.PeriodicProcesses {
|
||||
log.Printf("Invoking command: %s", v)
|
||||
exec.Command(v)
|
||||
time.Sleep(time.Duration(cnf.PeriodicProcessInvocationDelay) * time.Millisecond)
|
||||
}
|
||||
// Проходим по списку процессов и меняем ionice процессам.
|
||||
case <-processReniceTimer.C:
|
||||
// Не самый эффективный, зато работающий способ - простой перебор массивов.
|
||||
for _, p := range processList {
|
||||
ok := cnf.Pool.TrySubmit(func() {
|
||||
if processName, err := p.Name(); err == nil {
|
||||
// Для каждого процесса извлекаем его текущий priority.
|
||||
if currentPrioLevel, err := syscall.Getpriority(syscall.PRIO_PROCESS, int(p.Pid)); err == nil {
|
||||
if niceLevel := cnf.Renice[processName]; niceLevel != 0 {
|
||||
prioLevel := niceLevel
|
||||
currentNiceLevel := currentPrioLevel
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
// Value of PR = 20 + (-20 to +19) is 0 to 39
|
||||
switch {
|
||||
case niceLevel > 0:
|
||||
prioLevel = 20 - niceLevel
|
||||
case niceLevel < 0:
|
||||
prioLevel = 20 + int(math.Abs(float64(niceLevel)))
|
||||
default:
|
||||
prioLevel = 20
|
||||
}
|
||||
|
||||
currentNiceLevel = 20 - currentPrioLevel
|
||||
}
|
||||
|
||||
if currentPrioLevel != prioLevel {
|
||||
// on Linux Setpriority actually operates niceness value.
|
||||
_ = syscall.Setpriority(syscall.PRIO_PROCESS, int(p.Pid), niceLevel)
|
||||
|
||||
if cnf.Debug {
|
||||
log.Printf(
|
||||
"Set niceness for %s(%d) to %d (was %d)",
|
||||
processName,
|
||||
p.Pid,
|
||||
niceLevel,
|
||||
currentNiceLevel,
|
||||
)
|
||||
}
|
||||
} else if cnf.Debug {
|
||||
log.Printf(
|
||||
"Niceness for %s(%d) already set to %d",
|
||||
processName,
|
||||
p.Pid,
|
||||
niceLevel,
|
||||
currentNiceLevel,
|
||||
)
|
||||
}
|
||||
} else if cnf.Debug {
|
||||
log.Printf(
|
||||
"Niceness for %s(%d) already set to %d",
|
||||
processName,
|
||||
p.Pid,
|
||||
niceLevel,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
cnf.IORenice(p, processName)
|
||||
|
||||
// Посылаем процессу сигналы, если таковые есть в конфиге.
|
||||
if killSignal := cnf.KillSignal[processName]; killSignal != 0 {
|
||||
switch killSignal { //nolint:exhaustive
|
||||
case syscall.SIGSTOP:
|
||||
_ = p.SendSignal(killSignal)
|
||||
|
||||
if cnf.Debug {
|
||||
log.Printf(
|
||||
"Matching processName with killProcessname %s(%d), SIG%s sent",
|
||||
processName,
|
||||
p.Pid,
|
||||
strings.ToUpper(killSignal.String()),
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
_ = p.SendSignal(killSignal)
|
||||
|
||||
if cnf.Debug {
|
||||
log.Printf(
|
||||
"Matching processName with killProcessname %s(%d), SIG%s sent",
|
||||
processName,
|
||||
p.Pid,
|
||||
strings.ToUpper(killSignal.String()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
log.Printf("Unable to add task to pool. Increase nb_capacity?")
|
||||
}
|
||||
})
|
||||
|
||||
if !ok {
|
||||
log.Printf("Unable to add task to pool. Increase nb_capacity?")
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * time.Duration(cnf.LoopDelay))
|
||||
}
|
||||
|
||||
// Мы сюда никогда не попадём.
|
||||
|
||||
@@ -29,8 +29,26 @@ type Config struct {
|
||||
// Where to put pid-file.
|
||||
Pidfile string `yaml:"pidfile,omitempty"`
|
||||
|
||||
// LoopDelay in milliseconds - whole set of action delay period.
|
||||
LoopDelay int `yaml:"loop_delay,omitempty"`
|
||||
// ProcessListUpdatePeriod - delay between process list update task consecutive runs.
|
||||
ProcessListUpdatePeriod int `yaml:"process_list_update_period,omitempty"`
|
||||
|
||||
// ProcessKillPeriod in milliseconds - delay between kill consecutive tasks.
|
||||
ProcessKillPeriod int `yaml:"process_kill_period,omitempty"`
|
||||
|
||||
// ProcessNicePeriod in milliseconds - delay between changing niceness consecutive tasks.
|
||||
ProcessNicePeriod int `yaml:"process_nice_period,omitempty"`
|
||||
|
||||
// ProcessNicePeriod in milliseconds - delay between changing io niceness consecutive tasks (linux-only).
|
||||
ProcessIONicePeriod int `yaml:"process_ionice_period,omitempty"`
|
||||
|
||||
// PeriodicProcessInvocationPeriod in milliseconds - delay between PeriodicProcesses invocations.
|
||||
PeriodicProcessInvocationPeriod int `yaml:"periodic_process_invocation_period,omitempty"`
|
||||
|
||||
// PriodicProcessInvocationDelay in milliseconds - delay between each process calling in PeriodicProcesses list.
|
||||
PeriodicProcessInvocationDelay int `yaml:"periodic_process_invocation_delay,omitempty"`
|
||||
|
||||
// PeriodicProcesses list of processes that should be executed priodically.
|
||||
PeriodicProcesses []string `yaml:"periodic_process,omitempty"`
|
||||
|
||||
// Whether to print debug info on stdout.
|
||||
Debug bool `yaml:"debug,omitempty"`
|
||||
|
||||
@@ -70,9 +70,34 @@ func (cnf *Config) readConfFile(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if cnf.LoopDelay == 0 {
|
||||
cnf.LoopDelay = 2000
|
||||
log.Printf("loop_delay set to %d milliseconds", cnf.LoopDelay)
|
||||
if cnf.ProcessListUpdatePeriod == 0 {
|
||||
cnf.ProcessListUpdatePeriod = 5000
|
||||
log.Printf("process_list_update_priod set to %d milliseconds", cnf.ProcessListUpdatePeriod)
|
||||
}
|
||||
|
||||
if cnf.ProcessNicePeriod == 0 {
|
||||
cnf.ProcessNicePeriod = 5000
|
||||
log.Printf("process_nice_priod set to %d milliseconds", cnf.ProcessNicePeriod)
|
||||
}
|
||||
|
||||
if cnf.ProcessIONicePeriod == 0 {
|
||||
cnf.ProcessIONicePeriod = 5000
|
||||
log.Printf("process_ionice_period set to %d milliseconds", cnf.ProcessIONicePeriod)
|
||||
}
|
||||
|
||||
if cnf.ProcessKillPeriod == 0 {
|
||||
cnf.ProcessKillPeriod = 5000
|
||||
log.Printf("process_kill_period set to %d milliseconds", cnf.ProcessIONicePeriod)
|
||||
}
|
||||
|
||||
if cnf.PeriodicProcessInvocationPeriod == 0 {
|
||||
cnf.PeriodicProcessInvocationPeriod = 60000
|
||||
log.Printf("periodic_process_invocation_period set to %d milliseconds", cnf.PeriodicProcessInvocationPeriod)
|
||||
}
|
||||
|
||||
if cnf.PeriodicProcessInvocationDelay == 0 {
|
||||
cnf.PeriodicProcessInvocationDelay = 500
|
||||
log.Printf("periodic_process_invocation_delay set to %d milliseconds", cnf.PeriodicProcessInvocationDelay)
|
||||
}
|
||||
|
||||
if cnf.Debug {
|
||||
|
||||
Reference in New Issue
Block a user