hitman is a small library useful for cleaning up go routines
refered to as Targets.
A Target is required to implement a minimal interface for use with
Targets.Add(NamedTarget) or Targets.AddTarget(Target), namely a
Target must have a Start() hitman.KillChannel and a NamedTarget
must have both Name() string and Start() hitman.KillChannel. (The
difference is provided for convenience where a developer doesn't truly
care about naming the Target for logging purposes.)
See the example below which first creates a hitman.Targets instance
and then adds Targets using Add. When the application needs to
stop the collection of routines and allow those go routines to
shutdown gracefully it calls Targets.Close() which will send a
hitman.KillSignal to each routine allowing them to clean up and
shutdown gracefully.
// Components implement the Target interface and Start() KillChannel
type Component struct {}
func (w *Component) Start() KillChannel {
kill := NewKillChannel()
go func(done KillChannel) {
select {
case cleaner := <-done:
cleaner.WaitGroup.Done()
return
}
}(kill)
return kill
}
// Component lifecycles are then managed with a Targets collection:
func main() {
targets := NewTargets()
targets.Add(&Component{})
targets.Add(&Component{})
targets.Close()
}If you use the Death library then the example above can be written like so:
import (
DEATH "github.com/vrecan/death"
SYS "syscall"
)
type Service struct {}
func NewService() (*Server, error) {
s := &Service{}
// Do something that might produce error
_, err := ioutil.ReadFile("doh.txt")
return s, err
}
func main() {
targets := NewTargets()
targets.AddOrPanic(NewComponent())
targets.AddOrPanic(NewComponent())
//pass the signals you want to end your application
death := DEATH.NewDeath(SYS.SIGINT, SYS.SIGTERM)
// when you want to block for shutdown signals
// this will finish when a signal of your type is sent to your application
death.WaitForDeath(targets)
}- Revised the readme.
- Added
AddOrPanicfor services that return errors on construction (convenience). - Partitioned the
Targetinterface intoNamedandTargetso thatName()was optional. - Added Put that can take a given name instead of requiring the
Namedinterface. - Added tests for the above changes.
See license file.
The use and distribution terms for this software are covered by the Eclipse Public License 1.0, which can be found in the file 'license' at the root of this distribution. By using this software in any fashion, you are agreeing to be bound by the terms of this license. You must not remove this notice, or any other, from this software.