diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c9466126..374a272d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ BREAKING: - [cli] WriteDemoConfig -> WriteConfigValues + - [common] added Quit method to Service interface, which returns a channel + which is closed once a service is stopped ## 0.6.1 (TBD) diff --git a/common/service.go b/common/service.go index d70d16a80..2502d671c 100644 --- a/common/service.go +++ b/common/service.go @@ -35,9 +35,13 @@ type Service interface { // Return true if the service is running IsRunning() bool + // Quit returns a channel, which is closed once service is stopped. + Quit() <-chan struct{} + // String representation of the service String() string + // SetLogger sets a logger. SetLogger(log.Logger) } @@ -88,12 +92,13 @@ type BaseService struct { name string started uint32 // atomic stopped uint32 // atomic - Quit chan struct{} + quit chan struct{} // The "subclass" of BaseService impl Service } +// NewBaseService creates a new BaseService. func NewBaseService(logger log.Logger, name string, impl Service) *BaseService { if logger == nil { logger = log.NewNopLogger() @@ -102,16 +107,19 @@ func NewBaseService(logger log.Logger, name string, impl Service) *BaseService { return &BaseService{ Logger: logger, name: name, - Quit: make(chan struct{}), + quit: make(chan struct{}), impl: impl, } } +// SetLogger implements Service by setting a logger. func (bs *BaseService) SetLogger(l log.Logger) { bs.Logger = l } -// Implements Servce +// Start implements Service by calling OnStart (if defined). An error will be +// returned if the service is already running or stopped. Not to start the +// stopped service, you need to call Reset. func (bs *BaseService) Start() error { if atomic.CompareAndSwapUint32(&bs.started, 0, 1) { if atomic.LoadUint32(&bs.stopped) == 1 { @@ -133,17 +141,18 @@ func (bs *BaseService) Start() error { } } -// Implements Service +// OnStart implements Service by doing nothing. // NOTE: Do not put anything in here, // that way users don't need to call BaseService.OnStart() func (bs *BaseService) OnStart() error { return nil } -// Implements Service +// Stop implements Service by calling OnStop (if defined) and closing quit +// channel. An error will be returned if the service is already stopped. func (bs *BaseService) Stop() error { if atomic.CompareAndSwapUint32(&bs.stopped, 0, 1) { bs.Logger.Info(Fmt("Stopping %v", bs.name), "impl", bs.impl) bs.impl.OnStop() - close(bs.Quit) + close(bs.quit) return nil } else { bs.Logger.Debug(Fmt("Stopping %v (ignoring: already stopped)", bs.name), "impl", bs.impl) @@ -151,12 +160,13 @@ func (bs *BaseService) Stop() error { } } -// Implements Service +// OnStop implements Service by doing nothing. // NOTE: Do not put anything in here, // that way users don't need to call BaseService.OnStop() func (bs *BaseService) OnStop() {} -// Implements Service +// Reset implements Service by calling OnReset callback (if defined). An error +// will be returned if the service is running. func (bs *BaseService) Reset() error { if !atomic.CompareAndSwapUint32(&bs.stopped, 1, 0) { bs.Logger.Debug(Fmt("Can't reset %v. Not stopped", bs.name), "impl", bs.impl) @@ -166,41 +176,33 @@ func (bs *BaseService) Reset() error { // whether or not we've started, we can reset atomic.CompareAndSwapUint32(&bs.started, 1, 0) - bs.Quit = make(chan struct{}) + bs.quit = make(chan struct{}) return bs.impl.OnReset() } -// Implements Service +// OnReset implements Service by panicking. func (bs *BaseService) OnReset() error { PanicSanity("The service cannot be reset") return nil } -// Implements Service +// IsRunning implements Service by returning true or false depending on the +// service's state. func (bs *BaseService) IsRunning() bool { return atomic.LoadUint32(&bs.started) == 1 && atomic.LoadUint32(&bs.stopped) == 0 } +// Wait blocks until the service is stopped. func (bs *BaseService) Wait() { - <-bs.Quit + <-bs.quit } -// Implements Servce +// String implements Servce by returning a string representation of the service. func (bs *BaseService) String() string { return bs.name } -//---------------------------------------- - -type QuitService struct { - BaseService -} - -func NewQuitService(logger log.Logger, name string, impl Service) *QuitService { - if logger != nil { - logger.Info("QuitService is deprecated, use BaseService instead") - } - return &QuitService{ - BaseService: *NewBaseService(logger, name, impl), - } +// Quit Implements Service by returning a quit channel. +func (bs *BaseService) Quit() <-chan struct{} { + return bs.quit }