zrepl/cmd/daemon.go
Christian Schwarz e70b6f3071 WIP: recurring jobs
Done:

* implement autosnapper that asserts interval between snapshots
* implement pruner

* job pull: pulling + pruning
* job source: autosnapping + serving

TODO

* job source: pruning
* job local: everything
* fatal errors such as serve that cannot bind socket must be more
visible
* couldn't things that need a snapshotprefix just use a interface
Prefixer() instead? then we could have prefixsnapshotfilter and not
duplicate it every time...
* either go full context.Context or not at all...? just wait because
community climate around it isn't that great and we only need it for
cancellation? roll our own?
2017-09-15 19:35:19 +02:00

104 lines
1.7 KiB
Go

package cmd
import (
"context"
"fmt"
"github.com/spf13/cobra"
"os"
"os/signal"
"syscall"
)
// daemonCmd represents the daemon command
var daemonCmd = &cobra.Command{
Use: "daemon",
Short: "start daemon",
Run: doDaemon,
}
func init() {
RootCmd.AddCommand(daemonCmd)
}
type jobLogger struct {
MainLog Logger
JobName string
}
func (l jobLogger) Printf(format string, v ...interface{}) {
l.MainLog.Printf(fmt.Sprintf("[%s]: %s", l.JobName, format), v...)
}
type Job interface {
JobName() string
JobStart(ctxt context.Context)
}
func doDaemon(cmd *cobra.Command, args []string) {
d := Daemon{}
d.Loop()
}
type contextKey string
const (
contextKeyLog contextKey = contextKey("log")
)
type Daemon struct {
log Logger
}
func (d *Daemon) Loop() {
finishs := make(chan Job)
cancels := make([]context.CancelFunc, len(conf.Jobs))
log.Printf("starting jobs from config")
i := 0
for _, job := range conf.Jobs {
log.Printf("starting job %s", job.JobName())
logger := jobLogger{log, job.JobName()}
ctx := context.Background()
ctx, cancels[i] = context.WithCancel(ctx)
i++
ctx = context.WithValue(ctx, contextKeyLog, logger)
go func(j Job) {
job.JobStart(ctx)
finishs <- j
}(job)
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
finishCount := 0
outer:
for {
select {
case j := <-finishs:
log.Printf("job finished: %s", j.JobName())
finishCount++
if finishCount == len(conf.Jobs) {
log.Printf("all jobs finished")
break outer
}
case sig := <-sigChan:
log.Printf("received signal: %s", sig)
log.Printf("cancelling all jobs")
for _, c := range cancels {
log.Printf("cancelling job")
c()
}
}
}
signal.Stop(sigChan)
log.Printf("exiting")
}