Add socket activation for go apps
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
parent
cf90100c6c
commit
fb500991ec
1 changed files with 61 additions and 0 deletions
61
socketactivation/activation.go
Normal file
61
socketactivation/activation.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
Package to allow go applications to immediately start
|
||||||
|
listening on a socket, unix, tcp, udp but hold connections
|
||||||
|
until the application has booted and is ready to accept them
|
||||||
|
*/
|
||||||
|
package socketactivation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewActivationListener returns a listener listening on addr with the protocol. It sets the
|
||||||
|
// timeout to wait on first connection before an error is returned
|
||||||
|
func NewActivationListener(proto, addr string, activate chan struct{}, timeout time.Duration) (net.Listener, error) {
|
||||||
|
wrapped, err := net.Listen(proto, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &defaultListener{
|
||||||
|
wrapped: wrapped,
|
||||||
|
activate: activate,
|
||||||
|
timeout: timeout,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultListener struct {
|
||||||
|
wrapped net.Listener // the real listener to wrap
|
||||||
|
ready bool // is the listner ready to start accpeting connections
|
||||||
|
activate chan struct{}
|
||||||
|
timeout time.Duration // how long to wait before we consider this an error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *defaultListener) Close() error {
|
||||||
|
return l.wrapped.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *defaultListener) Addr() net.Addr {
|
||||||
|
return l.wrapped.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *defaultListener) Accept() (net.Conn, error) {
|
||||||
|
// if the listen has been told it is ready then we can go ahead and
|
||||||
|
// start returning connections
|
||||||
|
if l.ready {
|
||||||
|
return l.wrapped.Accept()
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(l.timeout):
|
||||||
|
// close the connection so any clients are disconnected
|
||||||
|
l.Close()
|
||||||
|
return nil, fmt.Errorf("timeout (%s) reached waiting for listener to become ready", l.timeout.String())
|
||||||
|
case <-l.activate:
|
||||||
|
l.ready = true
|
||||||
|
return l.Accept()
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue