tendermint/common/service.go

64 lines
1.7 KiB
Go

package common
import "sync/atomic"
// BaseService represents a service that can be started then stopped,
// but cannot be restarted.
// .Start() calls the onStart callback function, and .Stop() calls onStop.
// It is meant to be embedded into service structs.
// The user must ensure that Start() and Stop() are not called concurrently.
// It is ok to call Stop() without calling Start() first -- the onStop
// callback will be called, and the service will never start.
type BaseService struct {
name string
service interface{} // for log statements.
started uint32 // atomic
stopped uint32 // atomic
onStart func()
onStop func()
}
func NewBaseService(name string, service interface{}, onStart, onStop func()) *BaseService {
return &BaseService{
name: name,
service: service,
onStart: onStart,
onStop: onStop,
}
}
func (bs *BaseService) Start() bool {
if atomic.CompareAndSwapUint32(&bs.started, 0, 1) {
if atomic.LoadUint32(&bs.stopped) == 1 {
log.Warn(Fmt("Not starting %v -- already stopped", bs.name), "service", bs.service)
return false
} else {
log.Notice(Fmt("Starting %v", bs.name), "service", bs.service)
}
if bs.onStart != nil {
bs.onStart()
}
return true
} else {
log.Info(Fmt("Not starting %v -- already started", bs.name), "service", bs.service)
return false
}
}
func (bs *BaseService) Stop() bool {
if atomic.CompareAndSwapUint32(&bs.stopped, 0, 1) {
log.Notice(Fmt("Stopping %v", bs.name), "service", bs.service)
if bs.onStop != nil {
bs.onStop()
}
return true
} else {
log.Notice(Fmt("Not stopping %v", bs.name), "service", bs.service)
return false
}
}
func (bs *BaseService) IsRunning() bool {
return atomic.LoadUint32(&bs.started) == 1 && atomic.LoadUint32(&bs.stopped) == 0
}