Documentation ¶
Overview ¶
Package testing provides a stub implementation that can be used for simplified testing of applications that normally use tableflip. It is also helpful for allowing projects that use tableflip able to run on Windows, which does not support tableflip.
Example (HttpShutdown) ¶
This shows how to use the upgrader with the graceful shutdown facilities of net/http and using the stub implementation if on an unsupported platform.
package main import ( "context" "errors" "flag" "fmt" "log" "net" "net/http" "os" "os/signal" "syscall" "time" "github.com/cloudflare/tableflip" "github.com/cloudflare/tableflip/testing" ) type upgrader interface { Listen(network, addr string) (net.Listener, error) Stop() Upgrade() error Ready() error Exit() <-chan struct{} } // This shows how to use the upgrader // with the graceful shutdown facilities of net/http // and using the stub implementation if on an unsupported platform. func main() { var ( listenAddr = flag.String("listen", "localhost:8080", "`Address` to listen on") pidFile = flag.String("pid-file", "", "`Path` to pid file") ) flag.Parse() log.SetPrefix(fmt.Sprintf("%d ", os.Getpid())) var upg upgrader upg, err := tableflip.New(tableflip.Options{ PIDFile: *pidFile, }) if errors.Is(err, tableflip.ErrNotSupported) { upg, _ = testing.New() } else if err != nil { panic(err) } defer upg.Stop() // Do an upgrade on SIGHUP // NOTE: With `testing.Upgrader` this goroutine is useless // You may choose to enclose it inside an `if` statement block. go func() { sig := make(chan os.Signal, 1) signal.Notify(sig, syscall.SIGHUP) for range sig { err := upg.Upgrade() if err != nil { log.Println("Upgrade failed:", err) } } }() // Listen must be called before Ready ln, err := upg.Listen("tcp", *listenAddr) if err != nil { log.Fatalln("Can't listen:", err) } server := http.Server{ // Set timeouts, etc. } go func() { err := server.Serve(ln) if err != http.ErrServerClosed { log.Println("HTTP server:", err) } }() log.Printf("ready") if err := upg.Ready(); err != nil { panic(err) } <-upg.Exit() // Make sure to set a deadline on exiting the process // after upg.Exit() is closed. No new upgrades can be // performed if the parent doesn't exit. time.AfterFunc(30*time.Second, func() { log.Println("Graceful shutdown timed out") os.Exit(1) }) // Wait for connections to drain. server.Shutdown(context.Background()) }
Output:
Index ¶
- type Fds
- func (f *Fds) AddConn(network, addr string, conn net.Conn) error
- func (f *Fds) AddFile(name string, file *os.File) error
- func (f *Fds) AddListener(network, addr string, ln net.Listener) error
- func (f *Fds) Conn(network, addr string) (net.Conn, error)
- func (f *Fds) File(name string) (*os.File, error)
- func (f *Fds) Listen(network, addr string) (net.Listener, error)
- func (f *Fds) Listener(network, addr string) (net.Listener, error)
- type Upgrader
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Fds ¶
type Fds struct{}
func (*Fds) AddConn ¶
AddConn does nothing, since there is no reason to track connections in the stub implementation
func (*Fds) AddFile ¶
AddFile does nothing, since there is no reason to track connections in the stub implementation
func (*Fds) AddListener ¶
AddListener does nothing, since there is no reason to track connections in the stub implementation
func (*Fds) Conn ¶
Conn always returns nil, since it is impossible to inherit with the stub implementation
func (*Fds) File ¶
File always returns nil, since it is impossible to inherit with the stub implementation
type Upgrader ¶
type Upgrader struct {
*Fds
}
Upgrader has all the methods of tableflip.Upgrader, but they don't actually do anything special.
func (*Upgrader) Exit ¶
func (u *Upgrader) Exit() <-chan struct{}
Exit returns a channel which is closed when the process should exit. We can return nil here because reading from a nil channel blocks
func (*Upgrader) HasParent ¶
HasParent is always false, since the stub implementation can never have a parent
func (*Upgrader) Ready ¶
Ready does nothing, since it is impossible to inherit with the stub implementation. However, the function still needs to be callable without errors in order to be useful.
func (*Upgrader) Stop ¶
func (u *Upgrader) Stop()
Stop does nothing, since there will never be anything to stop in the stub implementation