@cryptotaxi247 / kubo / commits / 5a372f699

vendor manners - for real this time

sorry everyone.

Juan Batiz-Benet committed Nov 15, 2014 at 22:24 UTC 5a372f6996cd824634cc156d29d2db09c05d9dba
6 files changed +289
Godeps/_workspace/src/github.com/braintree/manners/LICENSE new
+19
@@ -0,0 +1,19 @@
1 +Copyright (c) 2014 Braintree, a division of PayPal, Inc.
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining a copy
4 +of this software and associated documentation files (the "Software"), to deal
5 +in the Software without restriction, including without limitation the rights
6 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +copies of the Software, and to permit persons to whom the Software is
8 +furnished to do so, subject to the following conditions:
9 +
10 +The above copyright notice and this permission notice shall be included in
11 +all copies or substantial portions of the Software.
12 +
13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 +THE SOFTWARE.
Godeps/_workspace/src/github.com/braintree/manners/README.md new
+33
@@ -0,0 +1,33 @@
1 +# Manners
2 +
3 +A *polite* webserver for Go.
4 +
5 +Manners allows you to shut your Go webserver down gracefully, without dropping any requests. It can act as a drop-in replacement for the standard library's http.ListenAndServe function:
6 +
7 +```go
8 +func main() {
9 + handler := MyHTTPHandler()
10 + server := manners.NewServer()
11 + server.ListenAndServe(":7000", handler)
12 +}
13 +```
14 +
15 +Then, when you want to shut the server down:
16 +
17 +```go
18 +server.Shutdown <- true
19 +```
20 +
21 +(Note that this does not block until all the requests are finished. Rather, the call to server.ListenAndServe will stop blocking when all the requests are finished.)
22 +
23 +Manners ensures that all requests are served by incrementing a WaitGroup when a request comes in and decrementing it when the request finishes.
24 +
25 +If your request handler spawns Goroutines that are not guaranteed to finish with the request, you can ensure they are also completed with the `StartRoutine` and `FinishRoutine` functions on the server.
26 +
27 +### Compatability
28 +
29 +Manners 0.3.0 and above uses standard library functionality introduced in Go 1.3.
30 +
31 +### Installation
32 +
33 +`go get github.com/braintree/manners`
Godeps/_workspace/src/github.com/braintree/manners/helper_test.go new
+34
@@ -0,0 +1,34 @@
1 +package manners
2 +
3 +import (
4 + "net/http"
5 + "time"
6 +)
7 +
8 +// A response handler that blocks until it receives a signal; simulates an
9 +// arbitrarily long web request. The "ready" channel is to prevent a race
10 +// condition in the test where the test moves on before the server is ready
11 +// to handle the request.
12 +func newBlockingHandler(ready, done chan bool) *blockingHandler {
13 + return &blockingHandler{ready, done}
14 +}
15 +
16 +type blockingHandler struct {
17 + ready chan bool
18 + done chan bool
19 +}
20 +
21 +func (h *blockingHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
22 + h.ready <- true
23 + time.Sleep(1e2)
24 + h.done <- true
25 +}
26 +
27 +// A response handler that does nothing.
28 +func newTestHandler() testHandler {
29 + return testHandler{}
30 +}
31 +
32 +type testHandler struct{}
33 +
34 +func (h testHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {}
Godeps/_workspace/src/github.com/braintree/manners/listener.go new
+49
@@ -0,0 +1,49 @@
1 +package manners
2 +
3 +import (
4 + "net"
5 + "sync"
6 +)
7 +
8 +func NewListener(l net.Listener, s *GracefulServer) *GracefulListener {
9 + return &GracefulListener{l, true, s, sync.RWMutex{}}
10 +}
11 +
12 +// A GracefulListener differs from a standard net.Listener in one way: if
13 +// Accept() is called after it is gracefully closed, it returns a
14 +// listenerAlreadyClosed error. The GracefulServer will ignore this
15 +// error.
16 +type GracefulListener struct {
17 + net.Listener
18 + open bool
19 + server *GracefulServer
20 + rw sync.RWMutex
21 +}
22 +
23 +func (l *GracefulListener) Accept() (net.Conn, error) {
24 + conn, err := l.Listener.Accept()
25 + if err != nil {
26 + l.rw.RLock()
27 + defer l.rw.RUnlock()
28 + if !l.open {
29 + err = listenerAlreadyClosed{err}
30 + }
31 + return nil, err
32 + }
33 + return conn, nil
34 +}
35 +
36 +func (l *GracefulListener) Close() error {
37 + l.rw.Lock()
38 + defer l.rw.Unlock()
39 + if !l.open {
40 + return nil
41 + }
42 + l.open = false
43 + err := l.Listener.Close()
44 + return err
45 +}
46 +
47 +type listenerAlreadyClosed struct {
48 + error
49 +}
Godeps/_workspace/src/github.com/braintree/manners/server.go new
+83
@@ -0,0 +1,83 @@
1 +package manners
2 +
3 +import (
4 + "net"
5 + "net/http"
6 + "sync"
7 +)
8 +
9 +// Creates a new GracefulServer. The server will begin shutting down when
10 +// a value is passed to the Shutdown channel.
11 +func NewServer() *GracefulServer {
12 + return &GracefulServer{
13 + Shutdown: make(chan bool),
14 + }
15 +}
16 +
17 +// A GracefulServer maintains a WaitGroup that counts how many in-flight
18 +// requests the server is handling. When it receives a shutdown signal,
19 +// it stops accepting new requests but does not actually shut down until
20 +// all in-flight requests terminate.
21 +type GracefulServer struct {
22 + Shutdown chan bool
23 + wg sync.WaitGroup
24 + shutdownHandler func()
25 + InnerServer http.Server
26 +}
27 +
28 +// A helper function that emulates the functionality of http.ListenAndServe.
29 +func (s *GracefulServer) ListenAndServe(addr string, handler http.Handler) error {
30 + oldListener, err := net.Listen("tcp", addr)
31 + if err != nil {
32 + return err
33 + }
34 +
35 + listener := NewListener(oldListener, s)
36 + err = s.Serve(listener, handler)
37 + return err
38 +}
39 +
40 +// Similar to http.Serve. The listener passed must wrap a GracefulListener.
41 +func (s *GracefulServer) Serve(listener net.Listener, handler http.Handler) error {
42 + s.shutdownHandler = func() { listener.Close() }
43 + s.listenForShutdown()
44 + s.InnerServer.Handler = handler
45 + s.InnerServer.ConnState = func(conn net.Conn, newState http.ConnState) {
46 + switch newState {
47 + case http.StateNew:
48 + s.StartRoutine()
49 + case http.StateClosed, http.StateHijacked:
50 + s.FinishRoutine()
51 + }
52 + }
53 + err := s.InnerServer.Serve(listener)
54 +
55 + // This block is reached when the server has received a shut down command.
56 + if err == nil {
57 + s.wg.Wait()
58 + return nil
59 + } else if _, ok := err.(listenerAlreadyClosed); ok {
60 + s.wg.Wait()
61 + return nil
62 + }
63 + return err
64 +}
65 +
66 +// Increments the server's WaitGroup. Use this if a web request starts more
67 +// goroutines and these goroutines are not guaranteed to finish before the
68 +// request.
69 +func (s *GracefulServer) StartRoutine() {
70 + s.wg.Add(1)
71 +}
72 +
73 +// Decrement the server's WaitGroup. Used this to complement StartRoutine().
74 +func (s *GracefulServer) FinishRoutine() {
75 + s.wg.Done()
76 +}
77 +
78 +func (s *GracefulServer) listenForShutdown() {
79 + go func() {
80 + <-s.Shutdown
81 + s.shutdownHandler()
82 + }()
83 +}
Godeps/_workspace/src/github.com/braintree/manners/server_test.go new
+71
@@ -0,0 +1,71 @@
1 +package manners
2 +
3 +import (
4 + "net/http"
5 + "testing"
6 +)
7 +
8 +// Tests that the server allows in-flight requests to complete before shutting
9 +// down.
10 +func TestGracefulness(t *testing.T) {
11 + ready := make(chan bool)
12 + done := make(chan bool)
13 +
14 + exited := false
15 +
16 + handler := newBlockingHandler(ready, done)
17 + server := NewServer()
18 +
19 + go func() {
20 + err := server.ListenAndServe(":7000", handler)
21 + if err != nil {
22 + t.Error(err)
23 + }
24 +
25 + exited = true
26 + }()
27 +
28 + go func() {
29 + _, err := http.Get("http://localhost:7000")
30 + if err != nil {
31 + t.Error(err)
32 + }
33 + }()
34 +
35 + // This will block until the server is inside the handler function.
36 + <-ready
37 +
38 + server.Shutdown <- true
39 + <-done
40 +
41 + if exited {
42 + t.Fatal("The request did not complete before server exited")
43 + } else {
44 + // The handler is being allowed to run to completion; test passes.
45 + }
46 +}
47 +
48 +// Tests that the server begins to shut down when told to and does not accept
49 +// new requests
50 +func TestShutdown(t *testing.T) {
51 + handler := newTestHandler()
52 + server := NewServer()
53 + exited := make(chan bool)
54 +
55 + go func() {
56 + err := server.ListenAndServe(":7100", handler)
57 + if err != nil {
58 + t.Error(err)
59 + }
60 + exited <- true
61 + }()
62 +
63 + server.Shutdown <- true
64 +
65 + <-exited
66 + _, err := http.Get("http://localhost:7100")
67 +
68 + if err == nil {
69 + t.Fatal("Did not receive an error when trying to connect to server.")
70 + }
71 +}