зеркало из https://github.com/golang/pkgsite.git
77 строки
1.8 KiB
Go
77 строки
1.8 KiB
Go
// Copyright 2020 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package poller supports periodic polling to load a value.
|
|
package poller
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// A Getter returns a value.
|
|
type Getter func(context.Context) (interface{}, error)
|
|
|
|
// A Poller maintains a current value, and refreshes it by periodically
|
|
// polling for a new value.
|
|
type Poller struct {
|
|
getter Getter
|
|
onError func(error)
|
|
mu sync.Mutex
|
|
current interface{}
|
|
}
|
|
|
|
// New creates a new poller with an initial value. The getter is invoked
|
|
// to obtain updated values. Errors returned from the getter are passed
|
|
// to onError.
|
|
func New(initial interface{}, getter Getter, onError func(error)) *Poller {
|
|
return &Poller{
|
|
getter: getter,
|
|
onError: onError,
|
|
current: initial,
|
|
}
|
|
}
|
|
|
|
// Start begins polling in a separate goroutine, at the given period. To stop
|
|
// the goroutine, cancel the context passed to Start.
|
|
func (p *Poller) Start(ctx context.Context, period time.Duration) {
|
|
ticker := time.NewTicker(period)
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
ticker.Stop()
|
|
return
|
|
case <-ticker.C:
|
|
ctx2, cancel := context.WithTimeout(ctx, period)
|
|
p.Poll(ctx2)
|
|
cancel()
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Poll calls p's getter immediately and synchronously.
|
|
func (p *Poller) Poll(ctx context.Context) {
|
|
next, err := p.getter(ctx)
|
|
if err != nil {
|
|
p.onError(err)
|
|
} else {
|
|
p.mu.Lock()
|
|
p.current = next
|
|
p.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
// Current returns the current value. Initially, this is the value passed to New.
|
|
// After each successful poll, the value is updated.
|
|
// If a poll fails, the value remains unchanged.
|
|
func (p *Poller) Current() interface{} {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
return p.current
|
|
}
|