backoff.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Copyright 2017 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package jsonclient
  15. import (
  16. "sync"
  17. "time"
  18. )
  19. type backoff struct {
  20. mu sync.RWMutex
  21. multiplier uint
  22. notBefore time.Time
  23. }
  24. const (
  25. // maximum backoff is 2^(maxMultiplier-1) = 128 seconds
  26. maxMultiplier = 8
  27. )
  28. func (b *backoff) set(override *time.Duration) time.Duration {
  29. b.mu.Lock()
  30. defer b.mu.Unlock()
  31. if b.notBefore.After(time.Now()) {
  32. if override != nil {
  33. // If existing backoff is set but override would be longer than
  34. // it then set it to that.
  35. notBefore := time.Now().Add(*override)
  36. if notBefore.After(b.notBefore) {
  37. b.notBefore = notBefore
  38. }
  39. }
  40. return time.Until(b.notBefore)
  41. }
  42. var wait time.Duration
  43. if override != nil {
  44. wait = *override
  45. } else {
  46. if b.multiplier < maxMultiplier {
  47. b.multiplier++
  48. }
  49. wait = time.Second * time.Duration(1<<(b.multiplier-1))
  50. }
  51. b.notBefore = time.Now().Add(wait)
  52. return wait
  53. }
  54. func (b *backoff) decreaseMultiplier() {
  55. b.mu.Lock()
  56. defer b.mu.Unlock()
  57. if b.multiplier > 0 {
  58. b.multiplier--
  59. }
  60. }
  61. func (b *backoff) until() time.Time {
  62. b.mu.RLock()
  63. defer b.mu.RUnlock()
  64. return b.notBefore
  65. }