graceful

package module
v0.0.0-...-377d7e4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2017 License: MIT Imports: 13 Imported by: 0

README ¶

Graceful 💎

GoDoc Travis

A library for sharing descriptors in Go.

Overview

Package graceful provides tools for sharing file descriptors between processes.

The most common reason to use it is the ability of so-called graceful restart of an application.

There is an example web application that restarts gracefully.

Usage

Graceful proposes a client-server mechanism of sharing file descriptors. That is, application that owns a descriptors is a server in graceful terminology, and an application that wants to receive those descriptors is a client.

The most common use of graceful looks like this:

// Somewhere close to the application initialization.
//
// By some logic we've decided to receive descriptors from currently running
// instance of the application.
var (
	ln   net.Listener
	file *os.File
)
err := graceful.Receive("/var/run/app.sock", func(fd int, meta io.Reader) error {
	// Handle received descriptor with concrete application logic.
	// 
	// meta is an additional information that corresponds to the descriptor and
	// represented by an io.Reader. User is free to select strategy of
	// marshaling/unmarshaling this information.
	if meta == nil {
		// In our example listener is passed with empty meta.
		ln = graceful.FdListener(fd)
		return nil
	}
	// There is a helper type called graceful.Meta that could be used to send
	// key-value pairs of meta without additional lines of code. Lets use it.
	m := new(graceful.Meta)
	if _, err := m.ReadFrom(meta); err != nil {
		// Prevent further interaction with the connection due to the error.
		return err
	}
	file = os.NewFile(fd, m["name"])
})
if err != nil {
	// Handle error.
}

...

// Somewhere close to the application termination.
//
// By some logic we've decided to send our descriptors to a new application
// instance that is probably just started.
//
// This code will send `ln` and `file` descriptors to every accepted
// connection on unix domain socket "/var/run/app.sock".
go graceful.ListenAndServe("/var/run/app.sock", graceful.SequenceHandler(
	graceful.ListenerHandler(ln, nil),
	graceful.FileHandler(file, graceful.Meta{
		"name": file.Name(),
	}),
))

That is, graceful does not force users to stick to some logic of processing restarts. It just provides mechanism for sharing descriptors in a client-server way.

If you have a more difficult logic of restarts, you could use less general API of graceful:

// Listen for an upcoming instance at the socket.
ln, err := net.Listen("unix", "/var/run/app.sock")
if err != nil {
	// Handle error.
}
defer ln.Close()

// Accept client connection from another application instance.
conn, err := ln.Accept()
if err != nil {
	// Handle error.
}
defer conn.Close()

// Send some application specific data first. This is useful when data is much
// larger than graceful i/o buffers and won't be putted in the descriptor meta.
if _, err := conn.Write(data); err != nil {
	// Handle error.
}

// Then send some descriptors to the connection.
graceful.SendListenerTo(conn, ln, nil)
graceful.SendListenerTo(conn, file, graceful.Meta{
	"name": file.Name(),
})

// Alternatively, you could send custom meta information with the fd.
//
// bytes.Buffer instance implements io.WriterTo, so wa are free to use it as
// meta argument for graceful.Send*() calls.
buf := new(bytes.Buffer)
buf.Write("Hello, I am meta!")

// Now send some descriptor with custom meta bytes.
// Client will receive io.Reader instance as meta that contains our simple
// string.
graceful.SendTo(conn, someFD, buf)

There is an example web application that handles restarts gracefully. Note that it does not handle SIGTERM signal just to show up that graceful if flexible and could be used in a simple way.

Status

This library is not tagged as stable version (and not tagged at all yet). This means that backward compatibility can be broken due some changes or refactoring.

Documentation ¶

Overview ¶

Package graceful provides tools for passing file descriptors between the applications.

It is intended to make graceful restarts of Go applications easier.

The very common example is:

ln, err := net.Listen("tcp", "localhost:")
if err != nil {
	// handle error
}

... // Work until must restart.

// Open a server that shares given listener with each accepted connection.
graceful.ListenAndServe(
	"/var/my_app/graceful.sock",
	graceful.ListenerHandler(ln),
)

Index ¶

Constants ¶

This section is empty.

Variables ¶

View Source
var (
	ErrEmptyControlMessage  = fmt.Errorf("empty control message")
	ErrEmptyFileDescriptors = fmt.Errorf("empty file descriptors")
)

Errors used by Receive() function.

View Source
var (
	// ErrNotUnixListener is returned by a Server when not a *net.UnixListener
	// is passed to its Serve() method.
	ErrNotUnixListener = errors.New("not a unix listener")

	// ErrLongWrite is returned by the ResponseWriter or Send* functions when
	// data that want be written is too large to be buffered.
	//
	// In this case user should send data separately to the client.
	//
	// Note that it is not possible to send messages larger than selected
	// buffer size because client still will not receive it due to that client
	// and server must use the same buffer size for reading and writing.
	ErrLongWrite = errors.New("long write")
)

Errors used by the Server and server helpers.

View Source
var ErrNotFiler = fmt.Errorf("given value does not provide *os.File getter")

ErrNotFiler returned when object given to Send* functios does provides ability for getting its underlying *os.File.

View Source
var ErrNotUnixConn = errors.New("not a unix connection")

ErrNotUnixConn is returned by a Client when not a *net.UnixConn is passed to its Receive* methods.

Functions ¶

func FdConn ¶

func FdConn(fd int) (net.Conn, error)

FdConn is a helper function that converts given descriptor to the net.Conn interface.

func FdListener ¶

func FdListener(fd int) (net.Listener, error)

FdListener is a helper function that converts given descriptor to the net.Listener interface.

func FdPacketConn ¶

func FdPacketConn(fd int) (net.PacketConn, error)

FdPacketConn is a helper function that converts given descriptor to the net.PacketConn interface.

func ListenAndServe ¶

func ListenAndServe(addr string, handler Handler) error

ListenAndServe creates Server instance with given handler and then calls server.ListenAndServe(addr) to handle incoming connections.

func Receive ¶

func Receive(addr string, cb ReceiveCallback) error

Receive dials to the "unix" network address addr and calls cb for each received descriptor from it until EOF.

func ReceiveAllFrom ¶

func ReceiveAllFrom(conn net.Conn, cb ReceiveCallback) error

ReceiveAllFrom reads all control messages from the given connection conn and calls cb for each descriptor inside those messages.

func ReceiveFrom ¶

func ReceiveFrom(conn net.Conn, cb ReceiveCallback) error

ReceiveFrom reads a single control message from the given connection conn and calls cb for each descriptor inside that message.

func Send ¶

func Send(addr string, fd int, meta io.WriterTo) error

Send dials to the "unix" network address addr and sends file descriptor to the peer.

func SendConn ¶

func SendConn(resp ResponseWriter, conn net.Conn, meta io.WriterTo) error

SendConn sends a connection conn with given meta to the ResponseWriter.

func SendConnTo ¶

func SendConnTo(dst, conn net.Conn, meta io.WriterTo) error

SendConnTo sends connection conn and its meta to the given connection dst.

func SendFile ¶

func SendFile(resp ResponseWriter, file *os.File, meta io.WriterTo) error

SendFile sends a file f with given meta to the ResponseWriter.

func SendFileTo ¶

func SendFileTo(conn net.Conn, file *os.File, meta io.WriterTo) error

SendFileTo sends file and its meta to the given conn.

func SendListener ¶

func SendListener(resp ResponseWriter, ln net.Listener, meta io.WriterTo) error

SendListener sends a listener ln with given meta to the ResponseWriter.

func SendListenerTo ¶

func SendListenerTo(conn net.Conn, ln net.Listener, meta io.WriterTo) error

SendListenerTo sends listener ln and its meta to the given conn.

func SendPacketConn ¶

func SendPacketConn(resp ResponseWriter, conn net.PacketConn, meta io.WriterTo) error

SendPacketConn sends a connection conn with given meta to the ResponseWriter.

func SendTo ¶

func SendTo(conn net.Conn, fd int, meta io.WriterTo) error

SendTo sends file descriptor fd and its meta to the given conn.

func Serve ¶

func Serve(ln net.Listener, handler Handler) error

Serve creates Server instance with given handler and then calls server.Serve(ln) to handle incoming connections.

Types ¶

type CallbackHandler ¶

type CallbackHandler func()

HandlerFunc is an adapter to allow the use of ordinary functions with empty arguments as Handlers.

func (CallbackHandler) Handle ¶

func (cb CallbackHandler) Handle(net.Conn, ResponseWriter)

Handle calls cb().

type Client ¶

type Client struct {
	// MsgBufferSize and OOBBufferSize defines an inner buffer sizes.
	//
	// MsgBufferSize defines size of the buffer for meta fields.
	// If MsgBufferSize is zero, then the default size is used.
	//
	// OOBBufferSize defines size of the buffer for serialized descriptors.
	// If OOBBufferSize is zero, then the default size is used.
	//
	// Note that client and server using this package MUST select the same
	// buffer sizes. Another option is to use the global functions which use
	// default sizes under the hood.
	MsgBufferSize, OOBBufferSize int
	// contains filtered or unexported fields
}

Client contains logic of parsing control messages.

func (*Client) Receive ¶

func (c *Client) Receive(addr string, cb ReceiveCallback) error

Receive dials to the "unix" network address addr and calls cb for each received descriptor.

func (*Client) ReceiveAllFrom ¶

func (c *Client) ReceiveAllFrom(conn net.Conn, cb ReceiveCallback) error

ReceiveAllFrom reads all control messages from the given connection conn and calls cb for each descriptor inside those messages.

func (*Client) ReceiveFrom ¶

func (c *Client) ReceiveFrom(conn net.Conn, cb ReceiveCallback) error

ReceiveFrom reads a single control message from the given connection conn and calls cb for each descriptor inside that message.

type DebugLogger ¶

type DebugLogger interface {
	Debugf(string, ...interface{})
}

DebugLogger interface is used by a Sever or a Client to log some debug information.

type ErrorLogger ¶

type ErrorLogger interface {
	Errorf(string, ...interface{})
}

ErrorLogger interface is used by a Sever or a Client to log some error information.

type Handler ¶

type Handler interface {
	Handle(net.Conn, ResponseWriter)
}

Handler describes an object that can send descriptors to the connection with given ResponseWriter.

func ConnHandler ¶

func ConnHandler(conn net.Conn, meta io.WriterTo) Handler

ConnHandler returns a Handler that sends conn with given meta to the received connection. If some error occures, it logs it by calling resp.Errorf().

func FdHandler ¶

func FdHandler(fd int, meta io.WriterTo) Handler

FdHandler returns a Handler that sends file descriptor with given meta to the received connection. If some error occures, it logs it by calling resp.Errorf().

func FileHandler ¶

func FileHandler(file *os.File, meta io.WriterTo) Handler

FileHandler returns a Handler that sends file with given meta to the received connection. If some error occures, it logs it by calling resp.Errorf().

func ListenerHandler ¶

func ListenerHandler(ln net.Listener, meta io.WriterTo) Handler

ListenerHandler returns a Handler that sends listener ln with given meta to the received connection. If some error occures, it logs it by calling resp.Errorf().

func PacketConnHandler ¶

func PacketConnHandler(conn net.PacketConn, meta io.WriterTo) Handler

PacketConnHandler returns a Handler that sends conn with given meta to the received connection. If some error occures, it logs it by calling resp.Errorf().

func SequenceHandler ¶

func SequenceHandler(hs ...Handler) Handler

SequenceHandler returns a Handler that calls Handle() method on each passed handlers in sequence.

type HandlerFunc ¶

type HandlerFunc func(net.Conn, ResponseWriter)

HandlerFunc is an adapter to allow the use of ordinary functions as Handlers.

func (HandlerFunc) Handle ¶

func (h HandlerFunc) Handle(conn net.Conn, resp ResponseWriter)

Handle calls h(conn, resp).

type InfoLogger ¶

type InfoLogger interface {
	Infof(string, ...interface{})
}

InfoLogger interface is used by a Sever or a Client to log some info information.

type Logger ¶

type Logger interface {
	DebugLogger
	InfoLogger
	ErrorLogger
}

Logger interface is used by a ResponseWriter to provide log methods for Handlers.

func LoggerFunc ¶

func LoggerFunc(debugf, infof, errorf func(string, ...interface{})) Logger

LoggerFunc creates Logger from given functions.

type Meta ¶

type Meta map[string]interface{}

Meta is a helper type that is marshaled/unmarshaled by `endoding/gob` package and could be used as an additional information for a descriptor.

func MetaFrom ¶

func MetaFrom(r io.Reader) (Meta, error)

func (*Meta) ReadFrom ¶

func (m *Meta) ReadFrom(r io.Reader) (int64, error)

func (Meta) WriteTo ¶

func (m Meta) WriteTo(w io.Writer) (int64, error)

type ReceiveCallback ¶

type ReceiveCallback func(fd int, meta io.Reader) error

ReceiveCallback describes a function that will be called on each received descriptor while parsing control messages. Its first argument is a received file descriptor. Its second argument is an optional meta information represented by an io.Reader.

If the callback returns non-nil error, then the function to which this callback was given exits immediately with that error.

Note that meta reader is only valid until callback returns. If server does not provide additional information for descriptor, meta argument will be nil.

type ResponseWriter ¶

type ResponseWriter interface {
	Logger
	// Write prepares file descriptor fd to be sent as well as an optional meta
	// information represented by an io.WriterTo.
	Write(fd int, meta io.WriterTo) error
}

ResponseWriter describes an object that can receive a descriptor.

type Server ¶

type Server struct {
	// MsgBufferSize defines size of the buffer for meta fields.
	// If MsgBufferSize is zero, then the default size is used.
	MsgBufferSize int

	// OOBBufferSize defines size of the buffer for serialized descriptors.
	// If OOBBufferSize is zero, then the default size is used.
	OOBBufferSize int

	// Handler is a neccessary field that contains logic of sending descriptors
	// to the every arrived connection.
	Handler Handler

	// Logger contains optional implementation of any *Logger interfaces
	// provided by this package.
	// If Logger is nil, then no logging is made.
	Logger interface{}
}

Server sends descriptors by calling Handler's Hanlde() method for every accepted connection.

Note that client and server using this package MUST select the same buffer sizes for the meta fields and descriptors. Another option is to use the global functions which use default sizes under the hood.

var DefaultServer Server

DefaultServer is an empty Server that is used by a Send* global functions as a method receiver.

func (*Server) ListenAndServe ¶

func (s *Server) ListenAndServe(addr string) error

ListenAndServe listens on the "unix" network address addr and then calls Serve to handle incoming connections.

func (*Server) SendConnTo ¶

func (s *Server) SendConnTo(dst, conn net.Conn, meta io.WriterTo) error

SendConnTo sends connection conn and its meta to the given connection dst.

func (*Server) SendFileTo ¶

func (s *Server) SendFileTo(conn net.Conn, file *os.File, meta io.WriterTo) error

SendFileTo sends file and its meta to the given conn.

func (*Server) SendListenerTo ¶

func (s *Server) SendListenerTo(conn net.Conn, ln net.Listener, meta io.WriterTo) error

SendListenerTo sends listener ln and its meta to the given conn.

func (*Server) SendTo ¶

func (s *Server) SendTo(conn net.Conn, fd int, meta io.WriterTo) error

SendTo sends file descriptor fd and its meta to the given conn.

func (*Server) Serve ¶

func (s *Server) Serve(l net.Listener) error

Serve accepts incoming connections on the listener l creating a new goroutine for each. That goroutine calls s.Handler.Handle(conn, rw) and exits.

Directories ¶

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL