redis

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2017 License: MIT Imports: 19 Imported by: 2

README

redis-go CircleCI Go Report Card GoDoc

Go package providing tools for building redis clients, servers and middleware.

Motivation

While there's already good client support for Redis in Go, when it comes to building middleware (which require server components) the landscape of options shrinks dramatically. The existing client libraries also have limitations when it comes to supporting newer Go features (like context.Context) and each of them adopts a different design, making it harder to integrate with other components of a system.
On the other hand, the standard net/http package has proven to have a simple, and still extensible design, making it possible to leverage composition to build software that is easier to develop, maintain and evolve.
This is where the redis-go package comes into play, it follows the same design than the standard net/http package while offering both client and server-side abstractions to build Redis-compatible software.

Client

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/segmentio/redis-go"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    // Use the default client which is configured to connect to the redis server
    // running at localhost:6379.
    if err := redis.Exec(ctx, "SET", "hello", "world"); err != nil {
        fmt.Println(err)
    }

    // Passing request or response arguments is done by consuming the stream of
    // values.
    var args = redis.Query(ctx, "GET", "hello")
    var value string

    if args.Next(&value) {
        fmt.Println(value)
    }

    if err := args.Close(); err != nil {
        fmt.Println(err)
    }
}

Server

package main

import (
    "github.com/segmentio/redis-go"
)

func main() {
    // Starts a new server speaking the redis protocol, the server automatically
    // handle asynchronusly pipelining the requests and responses.
    redis.ListenAndServe(":6380", redis.HandlerFunc(func(res redis.ResponseWriter, req *redis.Request) {
        // Put the response in streaming mode, will send 3 values.
        res.WriteStream(3)

        // The response writer automatically encodes Go values into their RESP
        // representation.
        res.Write(1)
        res.Write(2)
        res.Write(3)
    }))
}

Documentation

Overview

Package redis provides Redis client and server implementations.

Exec and Query make Redis requests.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrServerClosed is returned by Server.Serve when the server is closed.
	ErrServerClosed              = errors.New("redis: Server closed")
	ErrNegativeStreamCount       = errors.New("invalid call to redis.ResponseWriter.Stream with a negative value")
	ErrStreamCalledAfterWrite    = errors.New("invalid call to redis.ResponseWriter.Stream after redis.ResponseWriter.Write was called")
	ErrStreamCalledTooManyTimes  = errors.New("multiple calls to ResponseWriter.Stream")
	ErrWriteCalledTooManyTimes   = errors.New("too many calls to redis.ResponseWriter.Write")
	ErrWriteCalledNotEnoughTimes = errors.New("not enough calls to redis.ResponseWriter.Write")
	ErrHijacked                  = errors.New("invalid use of a hijacked redis.ResponseWriter")
)
View Source
var DefaultClient = &Client{}

DefaultClient is the default client and is used by Exec and Query.

View Source
var DefaultDialer = &net.Dialer{
	Timeout:   10 * time.Second,
	KeepAlive: 30 * time.Second,
	DualStack: true,
}

DefaultDialer is the default dialer used by Transports when no DialContext is set.

Functions

func Exec

func Exec(ctx context.Context, cmd string, args ...interface{}) error

Exec is a wrapper around DefaultClient.Exec.

func Int

func Int(args Args) (i int, err error)

Int parses an integer value from the list of arguments and closes it, returning an error if no integer could not be read.

func Int64

func Int64(args Args) (i int64, err error)

Int64 parses a 64 bits integer value from the list of arguments and closes it, returning an error if no integer could not be read.

func ListenAndServe

func ListenAndServe(addr string, handler Handler) error

ListenAndServe listens on the network address addr and then calls Serve with handler to handle requests on incoming connections.

ListenAndServe always returns a non-nil error.

func ParseArgs

func ParseArgs(args Args, dsts ...interface{}) error

ParseArgs reads a list of arguments into a sequence of destination pointers and closes it, returning any error that occurred while parsing the values.

func Serve

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

Serve accepts incoming Redis connections on the listener l, creating a new service goroutine for each. The service goroutines read requests and then call handler to reply to them.

Serve always returns a non-nil error.

func String

func String(args Args) (s string, err error)

String parses a string value from the list of arguments and closes it, returning an error if no string could not be read.

Types

type Args

type Args interface {
	// Close closes the argument list, returning any error that occurred while
	// reading the values.
	Close() error

	// Len returns the number of values remaining to be read from this argument
	// list.
	Len() int

	// Next reads the next value from the argument list into dst, which must be
	// a pointer.
	Next(dst interface{}) bool
}

Args represents a list of arguments in Redis requests and responses.

Args is an interface because there are multiple implementations that load values from memory, or from network connections. Using an interface allows the code consuming the list of arguments to be agnostic of the actual source from which the values are read.

func List

func List(args ...interface{}) Args

List creates an argument list from a sequence of values.

func MultiArgs

func MultiArgs(args ...Args) Args

MultiArgs returns an Args value that produces values sequentially from all of the given argument lists.

func Query

func Query(ctx context.Context, cmd string, args ...interface{}) Args

Query is a wrapper around DefaultClient.Query.

type Client

type Client struct {
	// Addr is the server address used by the client's Exec or Query methods
	// are called.
	Addr string

	// Transport specifies the mechanism by which individual requests are made.
	// If nil, DefaultTransport is used.
	Transport RoundTripper

	// Timeout specifies a time limit for requests made by this Client. The
	// timeout includes connection time, any redirects, and reading the response.
	// The timer remains running after Exec, Query, or Do return and will
	// interrupt reading of the Response.Args.
	//
	// A Timeout of zero means no timeout.
	Timeout time.Duration
}

A Client is a Redis client. Its zero value (DefaultClient) is a usable client that uses DefaultTransport and connects to a redis server on localhost:6379.

The Client's Transport typically has internal state (cached TCP connections), so Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines.

func (*Client) Do

func (c *Client) Do(req *Request) (*Response, error)

Do sends an Redis request and returns an Redis response.

An error is returned if the transport failed to contact the Redis server, or if a timeout occurs. Redis protocol errors are returned by the Response.Args' Close method.

If the error is nil, the Response will contain a non-nil Args which the user is expected to close. If the Body is not closed, the Client's underlying RoundTripper (typically Transport) may not be able to re-use a persistent TCP connection to the server for a subsequent request.

The request Args, if non-nil, will be closed by the underlying Transport, even on errors.

Generally Exec or Query will be used instead of Do.

func (*Client) Exec

func (c *Client) Exec(ctx context.Context, cmd string, args ...interface{}) error

Exec issues a request with cmd and args to the Redis server at the address set on the client.

An error is returned if the request couldn't be sent or if the command was refused by the Redis server.

The context passed as first argument allows the operation to be canceled asynchronously.

func (*Client) Query

func (c *Client) Query(ctx context.Context, cmd string, args ...interface{}) Args

Query issues a request with cmd and args to the Redis server at the address set on the client, returning the response's Args (which is never nil).

Any error occurring while querying the Redis server will be returned by the Args.Close method of the returned value.

The context passed as first argument allows the operation to be canceled asynchronously.

type Flusher

type Flusher interface {
	// Flush sends any buffered data to the client.
	Flush() error
}

The Flusher interface is implemented by ResponseWriters that allow a Redis handler to flush buffered data to the client.

type Handler

type Handler interface {
	// ServeRedis is called by a Redis server to handle requests.
	ServeRedis(ResponseWriter, *Request)
}

A Handler responds to a Redis request.

ServeRedis should write reply headers and data to the ResponseWriter and then return. Returning signals that the request is finished; it is not valid to use the ResponseWriter or read from the Request.Args after or concurrently with the completion of the ServeRedis call.

Except for reading the argument list, handlers should not modify the provided Request.

type HandlerFunc

type HandlerFunc func(ResponseWriter, *Request)

The HandlerFunc type is an adapter to allow the use of ordinary functions as Redis handlers. If f is a function with the appropriate signature.

func (HandlerFunc) ServeRedis

func (f HandlerFunc) ServeRedis(res ResponseWriter, req *Request)

ServeRedis implements the Handler interface, calling f.

type Hijacker

type Hijacker interface {
	// Hijack lets the caller take over the connection. After a call to Hijack
	// the Redis server library will not do anything else with the connection.
	//
	// It becomes the caller's responsibility to manage and close the
	// connection.
	//
	// The returned net.Conn may have read or write deadlines already set,
	// depending on the configuration of the Server. It is the caller's
	// responsibility to set or clear those deadlines as needed.
	//
	// The returned bufio.Reader may contain unprocessed buffered data from the
	// client.
	Hijack() (net.Conn, *bufio.ReadWriter, error)
}

The Hijacker interface is implemented by ResponseWriters that allow a Redis handler to take over the connection.

type Request

type Request struct {
	// For client requests, Addr is set to the address of the server to which
	// the request is sent.
	//
	// For server requests (when received in a Handler's ServeRedis method),
	// the Addr field contains the remote address of the client that sent the
	// request.
	Addr string

	// Cmd is the Redis command that's being sent with this request.
	Cmd string

	// Args is the list of arguments for the request's command. This field
	// may be nil for client requests if there are no arguments to send with
	// the request.
	//
	// For server request, Args is never nil, even if there are no values in
	// the argument list.
	Args Args

	// If not nil, this context is used to control asynchronous cancellation of
	// the request when it is passed to a RoundTripper.
	Context context.Context
	// contains filtered or unexported fields
}

A Request represents a Redis request received by a server or to be sent by a client.

The field semantics differ slightly between client and server usage. In addition to the notes on the fields below, see the documentation for Request.Write and RoundTripper.

func NewRequest

func NewRequest(addr string, cmd string, args Args) *Request

NewRequest returns a new Request, given an address, command, and list of arguments.

func (*Request) ParseArgs

func (req *Request) ParseArgs(dsts ...interface{}) error

ParseArgs parses the list of arguments from the request into the destination pointers, returning an error if something went wrong.

func (*Request) Write

func (req *Request) Write(w io.Writer) error

Write writes the request to w.

If the argument list is not nil, it is closed after being written.

type Response

type Response struct {
	// Args is the arguments list of the response.
	//
	// When the response is obtained from Transport.RoundTrip or from
	// Client.Do the Args field is never nil.
	Args Args

	// Request is the request that was sent to obtain this Response.
	Request *Request
}

Response represents the response from a Redis request.

func (*Response) Write

func (res *Response) Write(w io.Writer) error

Write writes the response to w.

If the argument list is not nil, it is closed after being written.

type ResponseWriter

type ResponseWriter interface {
	// WriteStream is called if the server handler is going to produce a list of
	// values by calling Write repeatedly n times.
	//
	// The method cannot be called more than once, or after Write was called.
	WriteStream(n int) error

	// Write is called by the server handler to send values back to the client.
	//
	// Write may not be called more than once, or more than n times, when n is
	// passed to a previous call to WriteStream.
	Write(v interface{}) error
}

A ResponseWriter interface is used by a Redis handler to construct an Redis response.

A ResponseWriter may not be used after the Handler.ServeRedis method has returned.

type ReverseProxy

type ReverseProxy struct {
	// Transport specifies the mechanism by which individual requests are made.
	// If nil, DefaultTransport is used.
	Transport RoundTripper

	// The registry exposing the set of redis servers that the proxy routes
	// requests to.
	Registry ServerRegistry

	// ErrorLog specifies an optional logger for errors accepting connections
	// and unexpected behavior from handlers. If nil, logging goes to os.Stderr
	// via the log package's standard logger.
	ErrorLog *log.Logger
}

ReverseProxy is the implementation of a redis reverse proxy.

func (*ReverseProxy) ServeRedis

func (proxy *ReverseProxy) ServeRedis(w ResponseWriter, r *Request)

ServeRedis satisfies the Handler interface.

type RoundTripper

type RoundTripper interface {
	// RoundTrip executes a single Redis transaction, returning/ a Response for
	// the provided Request.
	//
	// RoundTrip should not attempt to interpret the response. In particular,
	// RoundTrip must return err == nil if it obtained a response, regardless of
	// whether the response carries a protocol error. A non-nil err should be
	// reserved for failure to obtain a response.
	//
	// RoundTrip should not modify the request, except for consuming and closing
	// the Request's Args.
	//
	// RoundTrip must always close the argument list, including on errors, but
	// depending on the implementation may do so in a separate goroutine even
	// after RoundTrip returns. This means that callers wanting to reuse the
	// argument list for subsequent requests must arrange to wait for the Close
	// call before doing so.
	//
	// The Request's Addr and Cmd fields must be initialized.
	RoundTrip(*Request) (*Response, error)
}

RoundTripper is an interface representing the ability to execute a single Redis transaction, obtaining the Response for a given Request.

A RoundTripper must be safe for concurrent use by multiple goroutines.

var DefaultTransport RoundTripper = &Transport{
	ConnsPerHost: 4,
	PingTimeout:  10 * time.Second,
	PingInterval: 15 * time.Second,
}

DefaultTransport is the default implementation of Transport and is used by DefaultClient. It establishes network connections as needed and caches them for reuse by subsequent calls.

type Server

type Server struct {
	// The address to listen on, ":6379" if empty.
	//
	// The address may be prefixed with "tcp://" or "unix://" to specify the
	// type of network to listen on.
	Addr string

	// Handler invoked to handle Redis requests, must not be nil.
	Handler Handler

	// ReadTimeout is the maximum duration for reading the entire request,
	// including the reading the argument list.
	ReadTimeout time.Duration

	// WriteTimeout is the maximum duration before timing out writes of the
	// response. It is reset whenever a new request is read.
	WriteTimeout time.Duration

	// IdleTimeout is the maximum amount of time to wait for the next request.
	// If IdleTimeout is zero, the value of ReadTimeout is used. If both are
	// zero, there is no timeout.
	IdleTimeout time.Duration

	// ErrorLog specifies an optional logger for errors accepting connections
	// and unexpected behavior from handlers. If nil, logging goes to os.Stderr
	// via the log package's standard logger.
	ErrorLog *log.Logger
	// contains filtered or unexported fields
}

A Server defines parameters for running a Redis server.

func (*Server) Close

func (s *Server) Close() error

Close immediately closes all active net.Listeners and any connections. For a graceful shutdown, use Shutdown.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe listens on the network address s.Addr and then calls Serve to handle requests on incoming connections. If s.Addr is blank, ":6379" is used. ListenAndServe always returns a non-nil error.

func (*Server) Serve

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

Serve accepts incoming connections on the Listener l, creating a new service goroutine for each. The service goroutines read requests and then call s.Handler to reply to them.

Serve always returns a non-nil error. After Shutdown or Close, the returned error is ErrServerClosed.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the server without interrupting any active connections. Shutdown works by first closing all open listeners, then closing all idle connections, and then waiting indefinitely for connections to return to idle and then shut down. If the provided context expires before the shutdown is complete, then the context's error is returned.

type ServerEndpoint

type ServerEndpoint struct {
	Name string
	Addr string
}

A ServerEndpoint represents a single backend redis server.

func (ServerEndpoint) LookupServers

func (endpoint ServerEndpoint) LookupServers(ctx context.Context) ([]ServerEndpoint, error)

LookupServers satisfies the ServerRegistry interface.

type ServerList

type ServerList []ServerEndpoint

A ServerList represents a list of backend redis servers.

func (ServerList) LookupServers

func (list ServerList) LookupServers(ctx context.Context) ([]ServerEndpoint, error)

LookupServers satisfies the ServerRegistry interface.

type ServerRegistry

type ServerRegistry interface {
	// LookupServers returns a list of redis server endpoints.
	LookupServers(ctx context.Context) ([]ServerEndpoint, error)
}

The ServerRegistry interface is an abstraction used to expose a (potentially changing) list of backend redis servers.

type SubConn

type SubConn struct {
	// contains filtered or unexported fields
}

SubConn represents a redis connection that has been switched to PUB/SUB mode.

Instances of SubConn are safe for concurrent use by multiple goroutines.

func NewSubConn

func NewSubConn(conn net.Conn) *SubConn

NewSubConn creates a new SubConn from a pre-existing network connection.

func (*SubConn) Close

func (sub *SubConn) Close() error

Close closes the connection, writing commands or reading messages from the connection after Close was called will return errors.

func (*SubConn) LocalAddr

func (sub *SubConn) LocalAddr() net.Addr

LocalAddr returns the local network address.

func (*SubConn) ReadMessage

func (sub *SubConn) ReadMessage() (channel string, message []byte, err error)

ReadMessage reads the stream of PUB/SUB messages from the connection and returns the channel and payload of the first message it received.

The program is expected to call ReadMessage in a loop to consume messages from the PUB/SUB channels that the connection was subscribed to.

func (*SubConn) RemoteAddr

func (sub *SubConn) RemoteAddr() net.Addr

RemoteAddr returns the remote network address.

func (*SubConn) SetDeadline

func (sub *SubConn) SetDeadline(t time.Time) error

SetDeadline sets the read and write deadlines associated with the connection. It is equivalent to calling both SetReadDeadline and SetWriteDeadline.

A deadline is an absolute time after which I/O operations fail with a timeout (see type Error) instead of blocking. The deadline applies to all future and pending I/O, not just the immediately following call to ReadMessage or WriteCommand. After a deadline has been exceeded, the connection can be refreshed by setting a deadline in the future.

An idle timeout can be implemented by repeatedly extending the deadline after successful ReadFrom or WriteTo calls.

A zero value for t means I/O operations will not time out.

func (*SubConn) SetReadDeadline

func (sub *SubConn) SetReadDeadline(t time.Time) error

SetReadDeadline sets the deadline for future ReadFrom calls and any currently-blocked ReadFrom call. A zero value for t means ReadFrom will not time out.

func (*SubConn) SetWriteDeadline

func (sub *SubConn) SetWriteDeadline(t time.Time) error

SetWriteDeadline sets the deadline for future WriteTo calls and any currently-blocked WriteTo call. Even if write times out, it may return n > 0, indicating that some of the data was successfully written. A zero value for t means WriteTo will not time out.

func (*SubConn) WriteCommand

func (sub *SubConn) WriteCommand(command string, channels ...string) (err error)

WriteCommand writes a PUB/SUB command to the connection. The command must be one of "SUBSCRIBE", "UNSUBSCRIBE", "PSUBSCRIBE", or "PUNSUBSCRIBE".

type Transport

type Transport struct {
	// DialContext specifies the dial function for creating network connections.
	// If DialContext is nil, then the transport dials using package net.
	DialContext func(context.Context, string, string) (net.Conn, error)

	// ConnsPerHost controls the number of connections that are opened to each
	// host that is accessed by the transport.
	//
	// The default value used by this traansport is one.
	ConnsPerHost int

	// PingInterval is the amount of time between pings that the transport sends
	// to the hosts it connects to.
	PingInterval time.Duration

	// PingTimeout is the amount of time that the transport waits for responses
	// to ping requests before discarding connections.
	PingTimeout time.Duration
	// contains filtered or unexported fields
}

Transport is an implementation of RoundTripper.

By default, Transport caches connections for future re-use. This may leave many open connections when accessing many hosts. This behavior can be managed using Transport's CloseIdleConnections method and ConnsPerHost field.

Transports should be reused instead of created as needed. Transports are safe for concurrent use by multiple goroutines.

A Transport is a low-level primitive for making Redis requests. For high-level functionality, see Client.

func (*Transport) CloseIdleConnections

func (t *Transport) CloseIdleConnections()

CloseIdleConnections closes any connections which were previously connected from previous requests but are now sitting idle. It does not interrupt any connections currently in use.

func (*Transport) PSubscribe

func (t *Transport) PSubscribe(ctx context.Context, network string, address string, patterns ...string) (*SubConn, error)

Subscribe uses the transport's configuration to open a connection to a redis server that subscrribes to the given patterns.

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *Request) (*Response, error)

RoundTrip implements the RoundTripper interface.

For higher-level Redis client support, see Exec, Query, and the Client type.

func (*Transport) Subscribe

func (t *Transport) Subscribe(ctx context.Context, network string, address string, channels ...string) (*SubConn, error)

Subscribe uses the transport's configuration to open a connection to a redis server that subscrribes to the given channels.

Directories

Path Synopsis
cmd
red command
examples
client command
server command

Jump to

Keyboard shortcuts

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