// WatchValue returns a NotifyWatcher that triggers // when the given value changes. Its Wait and Err methods // never return a non-nil error. func WatchValue(val *voyeur.Value) state.NotifyWatcher { n := ¬ifier{ w: val.Watch(), changes: make(chan struct{}), } go n.loop() return n }
func (s *workerSuite) TestSetMembersErrorIsNotFatal(c *gc.C) { st := newFakeState() initState(c, st, 3) st.session.setStatus(mkStatuses("0p 1s 2s")) var isSet voyeur.Value count := 0 setErrorFuncFor("Session.Set", func() error { isSet.Set(count) count++ return errors.New("sample") }) s.PatchValue(&initialRetryInterval, 10*time.Microsecond) s.PatchValue(&maxRetryInterval, coretesting.ShortWait/4) expectedIterations := 0 for d := initialRetryInterval; d < maxRetryInterval*2; d *= 2 { expectedIterations++ } w := newWorker(st, noPublisher{}) defer func() { c.Check(worker.Stop(w), gc.IsNil) }() isSetWatcher := isSet.Watch() n0 := mustNext(c, isSetWatcher).(int) time.Sleep(maxRetryInterval * 2) n1 := mustNext(c, isSetWatcher).(int) // The worker should have backed off exponentially... c.Assert(n1-n0, jc.LessThan, expectedIterations+1) c.Logf("actual iterations %d; expected iterations %d", n1-n0, expectedIterations) // ... but only up to the maximum retry interval n0 = mustNext(c, isSetWatcher).(int) time.Sleep(maxRetryInterval * 2) n1 = mustNext(c, isSetWatcher).(int) c.Assert(n1-n0, jc.LessThan, 3) }