func (b *RetryBackoff) OnErr(error) bool {
	b.count++
	if b.count >= b.maxCount {
		return false
	}
	time.Sleep(b.interval)
	return true
}
OnErr implements Backoff.
package client
import (
	"context"
	"io/ioutil"
	"log"
	"time"
	"code.cloudfoundry.org/go-loggregator/rpc/loggregator_v2"
	"code.cloudfoundry.org/log-cache/pkg/rpc/logcache_v1"
)
type Reader func(
	ctx context.Context,
	sourceID string,
	start time.Time,
	opts ...ReadOption,
) ([]*loggregator_v2.Envelope, error)
type Visitor func([]*loggregator_v2.Envelope) bool
func Walk(ctx context.Context, sourceID string, v Visitor, r Reader, opts ...WalkOption) {
	c := &walkConfig{
		log:     log.New(ioutil.Discard, "", 0),
		backoff: AlwaysDoneBackoff{},
		delay:   time.Second,
	}
	for _, o := range opts {
		o.configure(c)
	}
	var readOpts []ReadOption
	if !c.end.IsZero() {
		readOpts = append(readOpts, WithEndTime(c.end))
	}
	if c.limit != nil {
		readOpts = append(readOpts, WithLimit(*c.limit))
	}
	if c.envelopeTypes != nil {
		readOpts = append(readOpts, WithEnvelopeTypes(c.envelopeTypes...))
	}
	if c.nameFilter != "" {
		readOpts = append(readOpts, WithNameFilter(c.nameFilter))
	}
	var receivedEmpty bool
	for {
		es, err := r(ctx, sourceID, time.Unix(0, c.start), readOpts...)
		if err != nil && ctx.Err() != nil {
			return
		}
		if err != nil {
			c.log.Print(err)
			if !c.backoff.OnErr(err) {
				return
			}
			continue
		}
		if c.end.IsZero() || !receivedEmpty {
			withDelay := time.Now().Add(-c.delay).UnixNano()
			for i := len(es) - 1; i >= 0; i-- {
				if es[i].GetTimestamp() <= withDelay {
					break
				}
				es = es[:i]
			}
		}
		if !c.end.IsZero() {
			for i := len(es) - 1; i >= 0; i-- {
				if es[i].GetTimestamp() < c.end.UnixNano() {
					break
				}
				es = es[:i]
			}
		}
		if len(es) == 0 {
			receivedEmpty = true
			if !c.backoff.OnEmpty() {
				return
			}
			continue
		}
		c.backoff.Reset()
		receivedEmpty = false
		if !v(es) || (!c.end.IsZero() && es[len(es)-1].Timestamp+1 >= c.end.UnixNano()) {
			return
		}
		c.start = es[len(es)-1].Timestamp + 1
	}
}
type WalkOption interface {
	configure(*walkConfig)
}
func WithWalkLogger(l *log.Logger) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.log = l
	})
}
func WithWalkStartTime(t time.Time) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.start = t.UnixNano()
	})
}
func WithWalkEndTime(t time.Time) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.end = t
	})
}
func WithWalkLimit(limit int) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.limit = &limit
	})
}
func WithWalkEnvelopeTypes(t ...logcache_v1.EnvelopeType) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.envelopeTypes = t
	})
}
func WithWalkNameFilter(nameFilter string) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.nameFilter = nameFilter
	})
}
func WithWalkBackoff(b Backoff) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.backoff = b
	})
}
func WithWalkDelay(delay time.Duration) WalkOption {
	return walkOptionFunc(func(c *walkConfig) {
		c.delay = delay
	})
}
type Backoff interface {
	OnErr(error) bool
	OnEmpty() bool
	Reset()
}
type AlwaysDoneBackoff struct{}
func (b AlwaysDoneBackoff) OnErr(error) bool {
	return false
}
func (b AlwaysDoneBackoff) OnEmpty() bool {
	return false
}
func (b AlwaysDoneBackoff) Reset() {}
type AlwaysRetryBackoff struct {
	interval time.Duration
}
func NewAlwaysRetryBackoff(interval time.Duration) AlwaysRetryBackoff {
	return AlwaysRetryBackoff{
		interval: interval,
	}
}
func (b AlwaysRetryBackoff) OnErr(error) bool {
	time.Sleep(b.interval)
	return true
}
func (b AlwaysRetryBackoff) OnEmpty() bool {
	time.Sleep(b.interval)
	return true
}
func (b AlwaysRetryBackoff) Reset() {}
type RetryBackoff struct {
	interval time.Duration
	maxCount int
	count    int
	onlyErr  bool
}
func NewRetryBackoff(interval time.Duration, maxCount int) *RetryBackoff {
	return &RetryBackoff{
		interval: interval,
		maxCount: maxCount,
	}
}
func NewRetryBackoffOnErr(interval time.Duration, maxCount int) *RetryBackoff {
	return &RetryBackoff{
		interval: interval,
		maxCount: maxCount,
		onlyErr:  true,
	}
}