1
0
Fork 0
shezmu/daemon.go

132 lines
3.3 KiB
Go
Raw Normal View History

2015-10-14 00:50:43 +00:00
package satan
2015-10-14 00:01:47 +00:00
2015-10-14 00:02:22 +00:00
import (
"fmt"
"log"
"runtime/debug"
2015-10-14 00:02:22 +00:00
"strings"
"time"
)
2015-10-14 00:01:47 +00:00
// Daemon is the interface that contains a set of methods required to be
// implemented in order to be treated as a daemon.
type Daemon interface {
2015-10-14 00:29:44 +00:00
// Startup implementation should:
2015-10-14 00:01:47 +00:00
//
// func (d *DaemonName) Startup() {
2015-10-14 00:29:44 +00:00
// // 1. Set up a panic handler
2015-10-14 00:01:47 +00:00
// b.HandlePanics(func() {
// log.Error("Oh, crap!")
// })
//
2015-10-14 00:29:44 +00:00
// // 2. If the daemon is also a consumer we need to subscribe for
// // topics that would be consumed by the daemon
2015-10-14 00:01:47 +00:00
// b.Subscribe("ProductPriceUpdates", func(p PriceUpdate) {
// log.Printf("Price for %q is now $%.2f", p.Product, p.Amount)
// })
//
2015-10-14 00:29:44 +00:00
// // 3. If the daemon is doing some IO it is a good idea to limit the
// // rate of its execution
// b.LimitRate(10, 1 * time.Second)
2015-10-14 00:01:47 +00:00
// }
Startup()
// Shutdown implementation should clean up all daemon related stuff:
// close channels, process the last batch of items, etc.
Shutdown()
// base is a (hack) function that allows the Daemon interface to reference
// underlying BaseDaemon structure.
base() *BaseDaemon
// initialize is also a hack that is used by the Satan to initialize
// base daemon fields.
initialize(self Daemon, queue chan<- *task)
}
2015-10-14 00:02:22 +00:00
// BaseDaemon is the parent structure for all daemons.
type BaseDaemon struct {
self Daemon
name string
stats *statistics
2015-10-14 01:11:29 +00:00
queue chan<- *task
2015-10-14 00:02:22 +00:00
panicHandler func()
shutdown chan struct{}
}
// Process creates a task and then adds it to processing queue.
func (d *BaseDaemon) Process(a Actor) {
d.enqueue(a, false)
}
// SystemProcess creates a system task that is restarted in case of failure
// and then adds it to processing queue.
func (d *BaseDaemon) SystemProcess(a Actor) {
d.enqueue(a, true)
}
func (d *BaseDaemon) enqueue(a Actor, system bool) {
d.queue <- &task{
daemon: d.self,
2015-10-14 00:02:22 +00:00
actor: a,
createdAt: time.Now(),
system: system,
2015-10-14 01:11:29 +00:00
}
2015-10-14 00:02:22 +00:00
}
// HandlePanics sets up a panic handler function for the daemon.
func (d *BaseDaemon) HandlePanics(f func()) {
d.panicHandler = f
2015-10-14 00:02:22 +00:00
}
// ShutdownRequested returns a channel that is closed the moment daemon shutdown
// is requested.
func (d *BaseDaemon) ShutdownRequested() <-chan struct{} {
return d.shutdown
2015-10-14 00:02:22 +00:00
}
2015-10-15 23:27:03 +00:00
// Continue returns true if daemon should proceed and false if it should stop.
func (d *BaseDaemon) Continue() bool {
select {
case <-d.shutdown:
return false
2015-10-15 23:27:03 +00:00
default:
return true
}
2015-10-14 00:02:22 +00:00
}
// String returns the name of the Deamon unerlying struct.
func (d *BaseDaemon) String() string {
if d.name == "" {
d.name = strings.Split(fmt.Sprintf("%T", d.self), ".")[1]
2015-10-14 00:02:22 +00:00
}
return d.name
2015-10-14 00:02:22 +00:00
}
// initialize saves a reference to the child daemon which is then used to print
// the daemons' name. It also initializes other struct fields.
func (d *BaseDaemon) initialize(self Daemon, queue chan<- *task) {
d.self = self
d.stats = newStatistics()
d.queue = queue
d.shutdown = make(chan struct{})
2015-10-14 00:02:22 +00:00
}
// base is a (hack) function that allows the Daemon interface to reference
// underlying BaseDaemon structure.
func (d *BaseDaemon) base() *BaseDaemon {
return d
2015-10-14 00:02:22 +00:00
}
func (d *BaseDaemon) handlePanic() {
2015-10-14 00:02:22 +00:00
if err := recover(); err != nil {
d.stats.registerError()
if d.panicHandler != nil {
d.panicHandler()
2015-10-14 00:02:22 +00:00
}
log.Printf("Daemon %s recovered from panic. Error: %v\n", d, err)
debug.PrintStack()
2015-10-14 00:02:22 +00:00
}
}