1
// Copyright 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
12
"github.com/juju/juju/apiserver/common"
13
"github.com/juju/juju/apiserver/facade"
14
"github.com/juju/juju/state"
15
"github.com/juju/utils/clock"
19
common.RegisterStandardFacade("Pinger", 1, NewPinger)
22
// NewPinger returns an object that can be pinged by calling its Ping method.
23
// If this method is not called frequently enough, the connection will be
25
func NewPinger(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (Pinger, error) {
26
pingTimeout, ok := resources.Get("pingTimeout").(*pingTimeout)
28
return nullPinger{}, nil
30
return pingTimeout, nil
33
// pinger describes a resource that can be pinged and stopped.
34
type Pinger interface {
39
// pingTimeout listens for pings and will call the
40
// passed action in case of a timeout. This way broken
41
// or inactive connections can be closed.
42
type pingTimeout struct {
50
// newPingTimeout returns a new pingTimeout instance
51
// that invokes the given action asynchronously if there
52
// is more than the given timeout interval between calls
53
// to its Ping method.
54
func newPingTimeout(action func(), clock clock.Clock, timeout time.Duration) Pinger {
59
reset: make(chan struct{}),
63
pt.tomb.Kill(pt.loop())
68
// Ping is used by the client heartbeat monitor and resets
70
func (pt *pingTimeout) Ping() {
72
case <-pt.tomb.Dying():
73
case pt.reset <- struct{}{}:
77
// Stop terminates the ping timeout.
78
func (pt *pingTimeout) Stop() error {
83
// loop waits for a reset signal, otherwise it performs
84
// the initially passed action.
85
func (pt *pingTimeout) loop() error {
88
case <-pt.tomb.Dying():
91
case <-pt.clock.After(pt.timeout):
93
return errors.New("ping timeout")
98
// nullPinger implements the pinger interface but just does nothing
99
type nullPinger struct{}
101
func (nullPinger) Ping() {}
102
func (nullPinger) Stop() error { return nil }