Change:
type timeBudgetImpl struct { sync.Mutex <del> budget time.Duration refresh   time.Duration </del> <ins> clock     clock.Clock budget    time.Duration </ins> maxBudget time.Duration <ins> refresh   time.Duration // last store last access time last time.Time </ins> } <del> func newTimeBudget(stopCh <-chan struct{}) timeBudget { </del> <ins> func newTimeBudget() timeBudget { </ins> result := &timeBudgetImpl{ <ins> clock:     clock.RealClock{}, </ins> budget:    time.Duration(0), refresh:   refreshPerSecond, maxBudget: maxBudget, } <del> go result.periodicallyRefresh(stopCh) </del> <ins> result.last = result.clock.Now() </ins> return result } <del> func (t *timeBudgetImpl) periodicallyRefresh(stopCh <-chan struct{}) { ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case <-ticker.C: t.Lock() if t.budget = t.budget + t.refresh; t.budget > t.maxBudget { t.budget = t.maxBudget } t.Unlock() case <-stopCh: return } } } </del> func (t *timeBudgetImpl) takeAvailable() time.Duration { t.Lock() defer t.Unlock() <ins> // budget accumulated since last access now := t.clock.Now() acc := now.Sub(t.last).Seconds() * t.refresh.Seconds() if acc < 0 { acc = 0 } // update current budget and store the current time if t.budget = t.budget + time.Duration(acc*1e9); t.budget > t.maxBudget { t.budget = t.maxBudget } t.last = now </ins> result := t.budget t.budget = time.Duration(0) return result

Discussion:
Instead of relying on the clock: we should do something similar to the golang rate-limitter is doing:
/sig api-machinery /priority important-longterm
/help
This request has been marked as needing help from a contributor. Please ensure the request meets the requirements listed . If this request no longer meets these requirements, the label can be removed by commenting with the command. <detailsIn response to : /help Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
Hi, I would like to help on this.
/assign Thanks! /triage accepted
can you please provide more context or some guidance on how to proceed?
Sorry for delayed response. - what we should do is to basically: instead of having an additional go-routine that every 1s refreshes the budget change it roughly to: (a) keep the value of budget and the last time when we were refreshing it (b) on takeAvailable method: first recompute takeAvailable, which will be "min(current budget + time elapsed since last refresh * refreshValue, maxAllowedBudget) update last refresh time to now return that value [We also would need to update the existing tests to match the new logic.] - would you be willing to work on it?
-- I can take this up. One question I had was should the method rely on or the current time should be passed on by the caller like in the following: Having the caller pass the time completely removes the dependency on the clock at least for the implementation.
/assign
Let's may be start with: passing on budget creation to it relying on
-- thank you for the thoughts. I drafted a rough implementation in which still depends on . I will make the change as you suggested and rely solely on a instance passed on initialization. I have to rethink the testing strategy a bit, possibly using a .
Yes - FakeClock is the way to test this.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-contributor-experience at . /lifecycle stale
/remove-lifecycle stale
Issues go stale after 90d of inactivity.

Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-contributor-experience at . /lifecycle stale
Stale issues rot after 30d of inactivity. Mark the issue as fresh with . Rotten issues close after an additional 30d of inactivity. If this issue is safe to close now please do so with . Send feedback to sig-contributor-experience at . /lifecycle rotten
Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . Send feedback to sig-contributor-experience at . /close
Closing this issue. <detailsIn response to : Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . /close Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
Reopening - this didn't happen.