Compare commits
4 Commits
816c3e1fc3
...
v0.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 9aa7097eef | |||
| 55904642d0 | |||
| 9425f1b3a9 | |||
| ba7983c375 |
114
examples/routines/main.go
Normal file
114
examples/routines/main.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Example routines demonstrates the use of routines and a routine manager.
|
||||
package main
|
||||
|
||||
import "log"
|
||||
import "time"
|
||||
import "context"
|
||||
import "math/rand"
|
||||
import "git.tebibyte.media/sashakoshka/go-service/daemon"
|
||||
import "git.tebibyte.media/sashakoshka/go-service/routines"
|
||||
|
||||
func main () {
|
||||
cow := cow { name: "cow" }
|
||||
sheep := sheep { name: "sheep" }
|
||||
horse := horse {
|
||||
name: "horse",
|
||||
sheep: &sheep,
|
||||
}
|
||||
|
||||
manager := routines.Manager {
|
||||
Routines: []routines.Routine {
|
||||
&cow,
|
||||
&sheep,
|
||||
&horse,
|
||||
},
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 12)
|
||||
daemon.OnSigint(cancel)
|
||||
err := manager.Run(ctx)
|
||||
if err != nil { log.Fatalln(err) }
|
||||
}
|
||||
|
||||
type cow struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (this *cow) Init (ctx context.Context) error {
|
||||
log.Printf("%s: waking up\n", this.name)
|
||||
defer log.Printf("%s: woke up\n", this.name)
|
||||
time.Sleep(time.Duration(float64(time.Second) * 4 * rand.Float64()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *cow) Run (ctx context.Context) error {
|
||||
log.Printf("%s: running\n", this.name)
|
||||
defer log.Printf("%s: going to sleep\n", this.name)
|
||||
|
||||
ticker := time.NewTicker(time.Duration(float64(time.Second) * 4 * rand.Float64()))
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <- ctx.Done(): return ctx.Err()
|
||||
case <- ticker.C: log.Printf("%s: moo\n", this.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type sheep struct {
|
||||
name string
|
||||
poke chan struct { }
|
||||
}
|
||||
|
||||
func (this *sheep) Init (ctx context.Context) error {
|
||||
log.Printf("%s: waking up\n", this.name)
|
||||
defer log.Printf("%s: woke up\n", this.name)
|
||||
this.poke = make(chan struct { })
|
||||
time.Sleep(time.Duration(float64(time.Second) * 4 * rand.Float64()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *sheep) Run (ctx context.Context) error {
|
||||
log.Printf("%s: running\n", this.name)
|
||||
defer log.Printf("%s: going to sleep\n", this.name)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <- ctx.Done(): return ctx.Err()
|
||||
case <- this.poke: log.Printf("%s: baa\n", this.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type horse struct {
|
||||
name string
|
||||
sheep *sheep
|
||||
}
|
||||
|
||||
func (this *horse) Init (ctx context.Context) error {
|
||||
log.Printf("%s: waking up\n", this.name)
|
||||
defer log.Printf("%s: woke up\n", this.name)
|
||||
time.Sleep(time.Duration(float64(time.Second) * 4 * rand.Float64()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *horse) Run (ctx context.Context) error {
|
||||
log.Printf("%s: running\n", this.name)
|
||||
defer log.Printf("%s: going to sleep\n", this.name)
|
||||
|
||||
ticker := time.NewTicker(time.Duration(float64(time.Second) * 4 * rand.Float64()))
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <- ctx.Done(): return ctx.Err()
|
||||
case <- ticker.C:
|
||||
if this.sheep != nil {
|
||||
log.Printf("%s: poking %s\n", this.name, this.sheep.name)
|
||||
this.sheep.poke <- struct { } { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ type Manager struct {
|
||||
// RestartDeadline specifies the amount of time a routine has to be
|
||||
// running before failing to be restarted. This is to prevent routines
|
||||
// that immediately fail from just being restarted over and over again.
|
||||
// Defaults to 32 seconds if not set.
|
||||
RestartDeadline time.Duration
|
||||
|
||||
// Logger, if non-nil, is where log messages will be written to. If it
|
||||
@@ -87,7 +88,7 @@ func (this *Manager) Run (ctx context.Context) error {
|
||||
waitGroup.Wait()
|
||||
|
||||
done()
|
||||
return nil
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// Append adds one or more routines to the Routines slice. This has no effect if
|
||||
@@ -123,12 +124,17 @@ func (this *Manager) initRoutine (routine Routine, group *sync.WaitGroup) {
|
||||
func (this *Manager) runRoutine (routine Routine, group *sync.WaitGroup) {
|
||||
defer group.Done()
|
||||
|
||||
restartDeadline := this.RestartDeadline
|
||||
if restartDeadline == 0 {
|
||||
restartDeadline = 32 * time.Second
|
||||
}
|
||||
|
||||
for {
|
||||
lastStart := time.Now()
|
||||
err := panicWrap(routine.Run, this.ctx)
|
||||
|
||||
if ctxErr := this.ctx.Err(); ctxErr != nil {
|
||||
if err == nil {
|
||||
if err == nil || errors.Is(err, context.Canceled) {
|
||||
this.log("(i) stopped routine")
|
||||
} else {
|
||||
this.log("!!! stopped routine, with error:", err)
|
||||
@@ -142,8 +148,8 @@ func (this *Manager) runRoutine (routine Routine, group *sync.WaitGroup) {
|
||||
} else {
|
||||
this.log("XXX routine failed:", err)
|
||||
}
|
||||
|
||||
if time.Since(lastStart) < this.RestartDeadline {
|
||||
|
||||
if time.Since(lastStart) < restartDeadline {
|
||||
this.log("!!! not restarting routine, failed too soon")
|
||||
break
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user