mirror of
https://github.com/rynbrd/go-service.git
synced 2024-07-22 16:58:31 +08:00
Implement Backoff state and modify restart behavior.
This commit is contained in:
parent
ae0f96dd2e
commit
77aa83ecfc
@ -13,10 +13,11 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Service defaults.
|
// Service defaults.
|
||||||
DefaultStopSignal = syscall.SIGINT
|
DefaultStartTimeout = 1 * time.Second
|
||||||
DefaultStopTimeout = 5 * time.Second
|
DefaultStartRetries = 3
|
||||||
DefaultRestart = true
|
DefaultStopSignal = syscall.SIGINT
|
||||||
DefaultRetries = 3
|
DefaultStopTimeout = 5 * time.Second
|
||||||
|
DefaultStopRestart = true
|
||||||
|
|
||||||
// Service commands.
|
// Service commands.
|
||||||
Start = "start"
|
Start = "start"
|
||||||
@ -30,7 +31,7 @@ const (
|
|||||||
Stopping = "stopping"
|
Stopping = "stopping"
|
||||||
Stopped = "stopped"
|
Stopped = "stopped"
|
||||||
Exited = "exited"
|
Exited = "exited"
|
||||||
//TODO: Implement Backoff state.
|
Backoff = "backoff"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command is sent to a Service to initiate a state change.
|
// Command is sent to a Service to initiate a state change.
|
||||||
@ -66,17 +67,18 @@ type Event struct {
|
|||||||
|
|
||||||
// Service represents a controllable process. Exported fields may be set to configure the service.
|
// Service represents a controllable process. Exported fields may be set to configure the service.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Directory string // The process's working directory. Defaults to the current directory.
|
Directory string // The process's working directory. Defaults to the current directory.
|
||||||
Environment []string // The environment of the process. Defaults to nil which indicatesA the current environment.
|
Environment []string // The environment of the process. Defaults to nil which indicatesA the current environment.
|
||||||
StopSignal syscall.Signal // The signal to send when stopping the process. Defaults to SIGINT.
|
StartTimeout time.Duration // How long the process has to run before it's considered Running.
|
||||||
StopTimeout time.Duration // How long to wait for a process to stop before sending a SIGKILL. Defaults to 5s.
|
StartRetries int // How many times to restart a process if it fails to start. Defaults to 3.
|
||||||
Restart bool // Whether or not to restart the process if it exits unexpectedly. Defaults to true.
|
StopSignal syscall.Signal // The signal to send when stopping the process. Defaults to SIGINT.
|
||||||
Retries int // How many times to restart a process if it fails to start. Defaults to 3.
|
StopTimeout time.Duration // How long to wait for a process to stop before sending a SIGKILL. Defaults to 5s.
|
||||||
Stdout io.Writer // Where to send the process's stdout. Defaults to /dev/null.
|
StopRestart bool // Whether or not to restart the process if it exits unexpectedly. Defaults to true.
|
||||||
Stderr io.Writer // Where to send the process's stderr. Defaults to /dev/null.
|
Stdout io.Writer // Where to send the process's stdout. Defaults to /dev/null.
|
||||||
args []string // The command line of the process to run.
|
Stderr io.Writer // Where to send the process's stderr. Defaults to /dev/null.
|
||||||
command *exec.Cmd // The os/exec command running the process.
|
args []string // The command line of the process to run.
|
||||||
state string // The state of the Service.
|
command *exec.Cmd // The os/exec command running the process.
|
||||||
|
state string // The state of the Service.
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new service with the default configution.
|
// New creates a new service with the default configution.
|
||||||
@ -85,10 +87,11 @@ func NewService(args []string) (svc *Service, err error) {
|
|||||||
svc = &Service{
|
svc = &Service{
|
||||||
cwd,
|
cwd,
|
||||||
nil,
|
nil,
|
||||||
|
DefaultStartTimeout,
|
||||||
|
DefaultStartRetries,
|
||||||
DefaultStopSignal,
|
DefaultStopSignal,
|
||||||
DefaultStopTimeout,
|
DefaultStopTimeout,
|
||||||
DefaultRestart,
|
DefaultStopRestart,
|
||||||
DefaultRetries,
|
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
args,
|
args,
|
||||||
@ -122,25 +125,6 @@ func (s Service) makeCommand() *exec.Cmd {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) startProcess(states chan string) (err error) {
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
//TODO: Do something with this error.
|
|
||||||
states <- Exited
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
s.command = s.makeCommand()
|
|
||||||
if err = s.command.Start(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
states <- Running
|
|
||||||
s.command.Wait()
|
|
||||||
states <- Exited
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Run(commands <-chan Command, events chan<- Event) {
|
func (s *Service) Run(commands <-chan Command, events chan<- Event) {
|
||||||
var lastCommand *Command
|
var lastCommand *Command
|
||||||
states := make(chan string)
|
states := make(chan string)
|
||||||
@ -166,13 +150,25 @@ func (s *Service) Run(commands <-chan Command, events chan<- Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start := func(cmd *Command) {
|
start := func(cmd *Command) {
|
||||||
if s.state != Stopped && s.state != Exited {
|
if s.state != Stopped && s.state != Exited && s.state != Backoff {
|
||||||
sendInvalidCmd(cmd, Starting)
|
sendInvalidCmd(cmd, Starting)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sendEvent(Starting)
|
sendEvent(Starting)
|
||||||
go s.startProcess(states)
|
go func() {
|
||||||
|
s.command = s.makeCommand()
|
||||||
|
startTime := time.Now()
|
||||||
|
if err := s.command.Start(); err == nil { //TODO: Don't swallow this error.
|
||||||
|
states <- Running
|
||||||
|
s.command.Wait()
|
||||||
|
if time.Now().Sub(startTime) > s.StartTimeout {
|
||||||
|
states <- Backoff
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states <- Exited
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
stop := func(cmd *Command) {
|
stop := func(cmd *Command) {
|
||||||
@ -220,7 +216,6 @@ func (s *Service) Run(commands <-chan Command, events chan<- Event) {
|
|||||||
stop(cmd)
|
stop(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retries = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onStopped := func(cmd *Command) {
|
onStopped := func(cmd *Command) {
|
||||||
@ -237,13 +232,22 @@ func (s *Service) Run(commands <-chan Command, events chan<- Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited := func(cmd *Command, retries int) bool {
|
onExited := func(cmd *Command) {
|
||||||
sendEvent(Exited)
|
sendEvent(Exited)
|
||||||
if s.Restart && retries < s.Retries {
|
if s.StopRestart {
|
||||||
start(cmd)
|
start(cmd)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
}
|
||||||
|
|
||||||
|
onBackoff := func(cmd *Command) {
|
||||||
|
if retries < s.StartRetries {
|
||||||
|
sendEvent(Backoff)
|
||||||
|
start(cmd)
|
||||||
|
retries++
|
||||||
|
} else {
|
||||||
|
sendEvent(Exited)
|
||||||
|
retries = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
@ -258,10 +262,10 @@ loop:
|
|||||||
if s.state == Stopping {
|
if s.state == Stopping {
|
||||||
onStopped(lastCommand)
|
onStopped(lastCommand)
|
||||||
} else {
|
} else {
|
||||||
if onExited(lastCommand, retries) {
|
onExited(lastCommand)
|
||||||
retries++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case Backoff:
|
||||||
|
onBackoff(lastCommand)
|
||||||
}
|
}
|
||||||
if lastCommand != nil {
|
if lastCommand != nil {
|
||||||
if lastCommand.Name == Restart && s.state == Running {
|
if lastCommand.Name == Restart && s.state == Running {
|
||||||
|
Loading…
Reference in New Issue
Block a user