repo move + timeout
This commit is contained in:
parent
2d7fb4c06a
commit
0a7f677b4a
79
grace.go
79
grace.go
@ -18,10 +18,13 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// This error is returned by Inherits() when we're not inheriting any fds.
|
// This error is returned by Inherits() when we're not inheriting any fds.
|
||||||
ErrNotInheriting = errors.New("no inherited listeners")
|
ErrNotInheriting = errors.New("grace: no inherited listeners")
|
||||||
|
|
||||||
// This error is returned by Listener.Accept() when Close is in progress.
|
// This error is returned by Listener.Accept() when Close is in progress.
|
||||||
ErrAlreadyClosed = errors.New("already closed")
|
ErrAlreadyClosed = errors.New("grace: already closed")
|
||||||
|
|
||||||
|
errRestartListeners = errors.New("grace: restart must be given listeners")
|
||||||
|
errTermTimeout = errors.New("grace: TERM timeout in closing listeners")
|
||||||
|
|
||||||
// Time in the past to trigger immediate deadline.
|
// Time in the past to trigger immediate deadline.
|
||||||
timeInPast = time.Now()
|
timeInPast = time.Now()
|
||||||
@ -142,35 +145,71 @@ func (l *listener) Accept() (net.Conn, error) {
|
|||||||
return &conn{Conn: c, wg: &l.wg}, nil
|
return &conn{Conn: c, wg: &l.wg}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process configures the restart process.
|
||||||
type Process struct {
|
type Process struct {
|
||||||
|
// TermTimeout if set will determine how long we'll wait for listeners when
|
||||||
|
// we're sent the TERM signal.
|
||||||
|
TermTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) term(listeners []Listener) error {
|
||||||
|
// shutdown all listeners in parallel
|
||||||
|
errs := make(chan error, len(listeners))
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(len(listeners))
|
||||||
|
for _, l := range listeners {
|
||||||
|
go func(l Listener) {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := l.Close(); err != nil {
|
||||||
|
errs <- err
|
||||||
|
}
|
||||||
|
}(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.TermTimeout.Nanoseconds() == 0 {
|
||||||
|
// no timeout, wait indefinitely
|
||||||
|
wg.Wait()
|
||||||
|
} else {
|
||||||
|
// wait in background to allow for implementing a timeout
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
wg.Wait()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// wait for graceful termination or timeout
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(p.TermTimeout):
|
||||||
|
return errTermTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if any errors occurred, return the first one
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return <-errs
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for signals to gracefully terminate or restart the process.
|
// Wait for signals to gracefully terminate or restart the process.
|
||||||
func (p *Process) Wait(listeners []Listener) (err error) {
|
func (p *Process) Wait(listeners []Listener) error {
|
||||||
ch := make(chan os.Signal, 2)
|
ch := make(chan os.Signal, 2)
|
||||||
signal.Notify(ch, syscall.SIGTERM, syscall.SIGUSR2)
|
signal.Notify(ch, syscall.SIGTERM, syscall.SIGUSR2)
|
||||||
for {
|
for {
|
||||||
sig := <-ch
|
sig := <-ch
|
||||||
switch sig {
|
switch sig {
|
||||||
case syscall.SIGTERM:
|
case syscall.SIGTERM:
|
||||||
|
// this ensures a subsequent TERM will trigger standard go behaviour of
|
||||||
|
// terminating.
|
||||||
signal.Stop(ch)
|
signal.Stop(ch)
|
||||||
var wg sync.WaitGroup
|
return p.term(listeners)
|
||||||
wg.Add(len(listeners))
|
|
||||||
for _, l := range listeners {
|
|
||||||
go func(l Listener) {
|
|
||||||
defer wg.Done()
|
|
||||||
cErr := l.Close()
|
|
||||||
if cErr != nil {
|
|
||||||
err = cErr
|
|
||||||
}
|
|
||||||
}(l)
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
return
|
|
||||||
case syscall.SIGUSR2:
|
case syscall.SIGUSR2:
|
||||||
rErr := Restart(listeners)
|
// we only return here if there's an error, otherwise the new process
|
||||||
if rErr != nil {
|
// will send us a TERM when it's ready to trigger the actual shutdown.
|
||||||
return rErr
|
if err := p.Restart(listeners); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +252,7 @@ func (p *Process) CloseParent() error {
|
|||||||
// Restart the process passing the given listeners to the new process.
|
// Restart the process passing the given listeners to the new process.
|
||||||
func (p *Process) Restart(listeners []Listener) (err error) {
|
func (p *Process) Restart(listeners []Listener) (err error) {
|
||||||
if len(listeners) == 0 {
|
if len(listeners) == 0 {
|
||||||
return errors.New("restart must be given listeners.")
|
return errRestartListeners
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the fds from the listeners.
|
// Extract the fds from the listeners.
|
||||||
|
@ -5,10 +5,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ParsePlatform/go.grace/gracehttp"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/facebookgo/grace/gracehttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/ParsePlatform/go.grace"
|
"github.com/facebookgo/grace"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -16,15 +16,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ParsePlatform/go.freeport"
|
"github.com/facebookgo/freeport"
|
||||||
"github.com/ParsePlatform/go.tool"
|
"github.com/facebookgo/tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Debug logging.
|
// Debug logging.
|
||||||
debugLog = flag.Bool("debug", false, "enable debug logging")
|
debugLog = flag.Bool("debug", false, "enable debug logging")
|
||||||
testserverCommand = &tool.CommandBuild{
|
testserverCommand = &tool.CommandBuild{
|
||||||
ImportPath: "github.com/ParsePlatform/go.grace/gracehttp/testserver",
|
ImportPath: "github.com/facebookgo/grace/gracehttp/testserver",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ParsePlatform/go.grace/gracehttp"
|
"github.com/facebookgo/grace/gracehttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type response struct {
|
type response struct {
|
||||||
|
10
readme.md
10
readme.md
@ -1,4 +1,4 @@
|
|||||||
go.grace [![Build Status](https://secure.travis-ci.org/ParsePlatform/go.grace.png)](http://travis-ci.org/ParsePlatform/go.grace)
|
go.grace [![Build Status](https://secure.travis-ci.org/facebookgo/grace.png)](http://travis-ci.org/facebookgo/grace)
|
||||||
========
|
========
|
||||||
|
|
||||||
Package grace provides a library that makes it easy to build socket
|
Package grace provides a library that makes it easy to build socket
|
||||||
@ -17,11 +17,11 @@ Usage
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
Demo HTTP Server with graceful termination and restart:
|
Demo HTTP Server with graceful termination and restart:
|
||||||
https://github.com/ParsePlatform/go.grace/blob/master/gracedemo/demo.go
|
https://github.com/facebookgo/grace/blob/master/gracedemo/demo.go
|
||||||
|
|
||||||
1. Install the demo application
|
1. Install the demo application
|
||||||
|
|
||||||
go get github.com/ParsePlatform/go.grace/gracedemo
|
go get github.com/facebookgo/grace/gracedemo
|
||||||
|
|
||||||
1. Start it in the first terminal
|
1. Start it in the first terminal
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ Documentation
|
|||||||
-------------
|
-------------
|
||||||
|
|
||||||
`http.Server` graceful termination and restart:
|
`http.Server` graceful termination and restart:
|
||||||
http://godoc.org/github.com/ParsePlatform/go.grace/gracehttp
|
http://godoc.org/github.com/facebookgo/grace/gracehttp
|
||||||
|
|
||||||
`net.Listener` graceful termination and restart:
|
`net.Listener` graceful termination and restart:
|
||||||
http://godoc.org/github.com/ParsePlatform/go.grace
|
http://godoc.org/github.com/facebookgo/grace
|
||||||
|
Loading…
Reference in New Issue
Block a user