Routine manager now recovers from panicking goroutines

This commit is contained in:
Sasha Koshka 2023-05-31 18:49:00 -04:00
parent 3cd53b3dd9
commit 92b645f34c

View File

@ -6,6 +6,7 @@ import "fmt"
import "log" import "log"
import "time" import "time"
import "sync" import "sync"
import "errors"
type routine struct { type routine struct {
run, shutdown func () error run, shutdown func () error
@ -71,17 +72,16 @@ type Manager struct {
// Run returns only when all routines have exited. // Run returns only when all routines have exited.
func (manager *Manager) Run () error { func (manager *Manager) Run () error {
var waitGroup sync.WaitGroup var waitGroup sync.WaitGroup
var errExit error
for _, routine := range manager.Routines { for _, routine := range manager.Routines {
if routine != nil { if routine != nil {
waitGroup.Add(1) waitGroup.Add(1)
go manager.runRoutine(routine, &waitGroup, &errExit) go manager.runRoutine(routine, &waitGroup)
} }
} }
waitGroup.Wait() waitGroup.Wait()
return errExit return nil
} }
// Shutdown shuts down all routines in the manager. // Shutdown shuts down all routines in the manager.
@ -113,20 +113,25 @@ func (manager *Manager) log (message ...any) {
} }
} }
func (manager *Manager) runRoutine (routine Routine, group *sync.WaitGroup, errExit *error) { func (manager *Manager) runRoutine (routine Routine, group *sync.WaitGroup) {
defer group.Done() defer group.Done()
var err error
for { for {
lastStart := time.Now()
err := panicWrap(routine.Run)
stopping := false stopping := false
manager.stoppingMutex.Lock() manager.stoppingMutex.Lock()
stopping = manager.stopping stopping = manager.stopping
manager.stoppingMutex.Unlock() manager.stoppingMutex.Unlock()
if stopping { break } if stopping {
if err == nil {
// TODO: recover from panics manager.log("(i) stopped routine")
lastStart := time.Now() } else {
err = routine.Run() manager.log("!!! stopped routine, with error:", err)
}
break
}
if err == nil { if err == nil {
manager.log("(i) routine exited") manager.log("(i) routine exited")
@ -142,8 +147,15 @@ func (manager *Manager) runRoutine (routine Routine, group *sync.WaitGroup, errE
manager.log("(i) routine is being restarted") manager.log("(i) routine is being restarted")
} }
} }
}
if err != nil {
*errExit = err func panicWrap (f func () error) (err error) {
} defer func () {
if pan := recover(); pan != nil {
err = errors.New(fmt.Sprint(pan))
}
} ()
err = f()
return
} }