// NewCrontab creates a cron server. func NewCrontab(freq time.Duration) *Crontab { c := &Crontab{ jobs: make(map[string]Job), commandChan: make(chan *command), ticker: time.NewTicker(freq), } c.loop = loop.GoRecoverable(c.backendLoop, c.checkRecovering) return c }
// NewStandardBackend starts the standard monitoring backend. func NewStandardBackend() Backend { m := &stdBackend{ measuringC: make(chan *stdMeasuring, 1024), ssvChangeC: make(chan *stdSSVChange, 1024), retrieverRegistrationC: make(chan *stdRetrieverRegistration, 16), commandC: make(chan *command), } m.backend = loop.GoRecoverable(m.backendLoop, m.checkRecovering) return m }
// newSystemMonitor starts the system monitor. func newSystemMonitor() *systemMonitor { m := &systemMonitor{ measuringChan: make(chan *Measuring, 1000), ssvChangeChan: make(chan *ssvChange, 1000), retrieverRegistrationChan: make(chan *retrieverRegistration, 10), commandChan: make(chan *command), } m.backend = loop.GoRecoverable(m.backendLoop, m.checkRecovering) return m }
// newCell create a new cell around a behavior. func newCell(env *environment, id string, behavior Behavior) (*cell, error) { logger.Infof("cell '%s' starts", id) // Init cell runtime. c := &cell{ env: env, id: id, measuringID: identifier.Identifier("cells", env.id, "cell", id), behavior: behavior, emitters: newConnections(), subscribers: newConnections(), emitTimeoutTicker: time.NewTicker(5 * time.Second), } // Set configuration. if bebs, ok := behavior.(BehaviorEventBufferSize); ok { size := bebs.EventBufferSize() if size < minEventBufferSize { size = minEventBufferSize } c.eventc = make(chan Event, size) } else { c.eventc = make(chan Event, minEventBufferSize) } if brf, ok := behavior.(BehaviorRecoveringFrequency); ok { number, duration := brf.RecoveringFrequency() if duration.Seconds()/float64(number) < 0.1 { number = minRecoveringNumber duration = minRecoveringDuration } c.recoveringNumber = number c.recoveringDuration = duration } else { c.recoveringNumber = minRecoveringNumber c.recoveringDuration = minRecoveringDuration } if bet, ok := behavior.(BehaviorEmitTimeout); ok { timeout := bet.EmitTimeout() switch { case timeout < minEmitTimeout: timeout = minEmitTimeout case timeout > maxEmitTimeout: timeout = maxEmitTimeout } c.emitTimeout = int(timeout.Seconds() / 5) } else { c.emitTimeout = int(maxEmitTimeout.Seconds() / 5) } // Init behavior. if err := behavior.Init(c); err != nil { return nil, errors.Annotate(err, ErrCellInit, errorMessages, id) } // Start backend. c.loop = loop.GoRecoverable(c.backendLoop, c.checkRecovering, id) return c, nil }
// TestEndRecoverings tests the regular internal stop of a recovered loop. func TestEndRecoverings(t *testing.T) { assert := audit.NewTestingAssertion(t, true) done := false count := 0 l := loop.GoRecoverable(generateRecoverNoErrorBackend(&done, &count), ignorePanics) time.Sleep(longDelay) status, _ := l.Error() assert.Equal(loop.Stopped, status) }
// TestStopRecoverings tests the regular stop of a recovered loop. func TestStopRecoverings(t *testing.T) { assert := audit.NewTestingAssertion(t, true) done := false count := 0 l := loop.GoRecoverable(generateRecoverPanicBackend(&done, &count), ignorePanics) time.Sleep(longDelay) assert.Nil(l.Stop(), "no error after simple stop") assert.True(done, "backend has done") status, _ := l.Error() assert.Equal(loop.Stopped, status, "loop is stopped") }
// TestRecoveringsError tests recoverings after errors func TestRecoveringsError(t *testing.T) { assert := audit.NewTestingAssertion(t, true) done := false count := 0 l := loop.GoRecoverable(generateRecoverErrorBackend(&done, &count), catchTimeout) time.Sleep(longDelay) assert.ErrorMatch(l.Stop(), "timed out", "error has to be 'timed out'") assert.True(done, "backend has done") status, _ := l.Error() assert.Equal(loop.Stopped, status, "loop is stopped") }
// TestRecoveringsPanic test recoverings after panics. func TestRecoveringsPanic(t *testing.T) { assert := audit.NewTestingAssertion(t, true) done := false count := 0 l := loop.GoRecoverable(generateRecoverPanicBackend(&done, &count), checkRecovering) time.Sleep(veryLongDelay) assert.ErrorMatch(l.Stop(), "too many panics") assert.True(done) assert.Equal(count, 5) status, _ := l.Error() assert.Equal(loop.Stopped, status) }
// Test recoverings after panics. func TestRecoverings(t *testing.T) { assert := audit.NewTestingAssertion(t, true) done := false count := 0 l := loop.GoRecoverable(generateSimplePanicBackend(&done, &count), checkRecovering) time.Sleep(veryLongDelay) assert.ErrorMatch(l.Stop(), "too many panics", "error has to be 'too many panics'") assert.True(done, "backend has done") assert.Equal(count, 5, "loop has to be restarted 5 times") status, _ := l.Error() assert.Equal(loop.Stopped, status, "loop is stopped") }
func ExampleRecoverFunc() { printChan := make(chan string) loopFunc := func(l loop.Loop) error { for { select { case <-l.ShallStop(): return nil case str := <-printChan: println(str) } } } recoverFunc := func(rs loop.Recoverings) (loop.Recoverings, error) { if len(rs) >= 5 { return nil, errors.New("too many panics") } return rs, nil } loop.GoRecoverable(loopFunc, recoverFunc) }