From 5f98fcd9ec2fa29c864b9090ada8ae1e94bd8cb9 Mon Sep 17 00:00:00 2001 From: Daniel Theophanes Date: Fri, 5 Feb 2016 09:48:50 -0800 Subject: [PATCH] service: update API to allow for programs that install their own signal handlers. --- service.go | 25 +++++++++++++++++++++---- service_darwin.go | 10 +++++----- service_systemd_linux.go | 13 ++++++++----- service_sysv_linux.go | 10 +++++----- service_upstart_linux.go | 10 +++++----- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/service.go b/service.go index ca0c83d..fcef802 100644 --- a/service.go +++ b/service.go @@ -78,6 +78,9 @@ const ( optionUserServiceDefault = false optionSessionCreate = "SessionCreate" optionSessionCreateDefault = false + + optionRunWait = "RunWait" + optionReloadSignal = "ReloadSignal" ) // Config provides the setup for a Service. The Name field is required. @@ -106,6 +109,9 @@ type Config struct { // - RunAtLoad bool (false) // - UserService bool (false) - Install as a current user service. // - SessionCreate bool (false) - Create a full user session. + // * POSIX + // - RunWait func() (wait for SIGNAL) - Do not install signal but wait for this function to return. + // - ReloadSignal string () [USR1, ...] - Signal to send on reaload. Option KeyValue } @@ -143,7 +149,7 @@ func New(i Interface, c *Config) (Service, error) { // more details. type KeyValue map[string]interface{} -// Bool returns the value of the given name, assuming the value is a boolean. +// bool returns the value of the given name, assuming the value is a boolean. // If the value isn't found or is not of the type, the defaultValue is returned. func (kv KeyValue) bool(name string, defaultValue bool) bool { if v, found := kv[name]; found { @@ -154,7 +160,7 @@ func (kv KeyValue) bool(name string, defaultValue bool) bool { return defaultValue } -// Int returns the value of the given name, assuming the value is an int. +// int returns the value of the given name, assuming the value is an int. // If the value isn't found or is not of the type, the defaultValue is returned. func (kv KeyValue) int(name string, defaultValue int) int { if v, found := kv[name]; found { @@ -165,7 +171,7 @@ func (kv KeyValue) int(name string, defaultValue int) int { return defaultValue } -// Int returns the value of the given name, assuming the value is a string. +// string returns the value of the given name, assuming the value is a string. // If the value isn't found or is not of the type, the defaultValue is returned. func (kv KeyValue) string(name string, defaultValue string) string { if v, found := kv[name]; found { @@ -176,7 +182,7 @@ func (kv KeyValue) string(name string, defaultValue string) string { return defaultValue } -// Int returns the value of the given name, assuming the value is a float64. +// float64 returns the value of the given name, assuming the value is a float64. // If the value isn't found or is not of the type, the defaultValue is returned. func (kv KeyValue) float64(name string, defaultValue float64) float64 { if v, found := kv[name]; found { @@ -187,6 +193,17 @@ func (kv KeyValue) float64(name string, defaultValue float64) float64 { return defaultValue } +// funcSingle returns the value of the given name, assuming the value is a float64. +// If the value isn't found or is not of the type, the defaultValue is returned. +func (kv KeyValue) funcSingle(name string, defaultValue func()) func() { + if v, found := kv[name]; found { + if castValue, is := v.(func()); is { + return castValue + } + } + return defaultValue +} + // Platform returns a description of the system service. func Platform() string { if system == nil { diff --git a/service_darwin.go b/service_darwin.go index a8278b3..0a28962 100644 --- a/service_darwin.go +++ b/service_darwin.go @@ -196,11 +196,11 @@ func (s *darwinLaunchdService) Run() error { return err } - var sigChan = make(chan os.Signal, 3) - - signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) - - <-sigChan + s.Option.funcSingle(optionRunWait, func() { + var sigChan = make(chan os.Signal, 3) + signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) + <-sigChan + })() return s.i.Stop(s) } diff --git a/service_systemd_linux.go b/service_systemd_linux.go index 77371d1..6d7f590 100644 --- a/service_systemd_linux.go +++ b/service_systemd_linux.go @@ -80,9 +80,11 @@ func (s *systemd) Install() error { var to = &struct { *Config Path string + ReloadSignal string }{ s.Config, path, + s.Option.string(optionReloadSignal, ""), } err = s.template().Execute(f, to) @@ -128,11 +130,11 @@ func (s *systemd) Run() (err error) { return err } - sigChan := make(chan os.Signal, 3) - - signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) - - <-sigChan + s.Option.funcSingle(optionRunWait, func() { + var sigChan = make(chan os.Signal, 3) + signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) + <-sigChan + })() return s.i.Stop(s) } @@ -160,6 +162,7 @@ ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}} {{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}} {{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmd}}{{end}} {{if .UserName}}User={{.UserName}}{{end}} +{{if .ReloadSignal}}ExecReload=/bin/kill -{{.ReloadSignal}} "$MAINPID"{{end}} Restart=always RestartSec=120 diff --git a/service_sysv_linux.go b/service_sysv_linux.go index 625fbb7..352847a 100644 --- a/service_sysv_linux.go +++ b/service_sysv_linux.go @@ -127,11 +127,11 @@ func (s *sysv) Run() (err error) { return err } - sigChan := make(chan os.Signal, 3) - - signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) - - <-sigChan + s.Option.funcSingle(optionRunWait, func() { + var sigChan = make(chan os.Signal, 3) + signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) + <-sigChan + })() return s.i.Stop(s) } diff --git a/service_upstart_linux.go b/service_upstart_linux.go index 3703ece..2adeea8 100644 --- a/service_upstart_linux.go +++ b/service_upstart_linux.go @@ -117,11 +117,11 @@ func (s *upstart) Run() (err error) { return err } - sigChan := make(chan os.Signal, 3) - - signal.Notify(sigChan, os.Interrupt, os.Kill) - - <-sigChan + s.Option.funcSingle(optionRunWait, func() { + var sigChan = make(chan os.Signal, 3) + signal.Notify(sigChan, os.Interrupt, os.Kill) + <-sigChan + })() return s.i.Stop(s) }