Documentation ¶
Index ¶
- Constants
- type AliveNodes
- type Cluster
- func (cl *Cluster) Alive() Node
- func (cl *Cluster) Close() error
- func (cl *Cluster) Err() error
- func (cl *Cluster) Node(criteria NodeStateCriteria) Node
- func (cl *Cluster) Nodes() []Node
- func (cl *Cluster) Primary() Node
- func (cl *Cluster) PrimaryPreferred() Node
- func (cl *Cluster) Standby() Node
- func (cl *Cluster) StandbyPreferred() Node
- func (cl *Cluster) WaitForAlive(ctx context.Context) (Node, error)
- func (cl *Cluster) WaitForNode(ctx context.Context, criteria NodeStateCriteria) (Node, error)
- func (cl *Cluster) WaitForPrimary(ctx context.Context) (Node, error)
- func (cl *Cluster) WaitForPrimaryPreferred(ctx context.Context) (Node, error)
- func (cl *Cluster) WaitForStandby(ctx context.Context) (Node, error)
- func (cl *Cluster) WaitForStandbyPreferred(ctx context.Context) (Node, error)
- type ClusterOption
- type CollectedErrors
- type Node
- type NodeChecker
- type NodeError
- type NodePicker
- type NodeStateCriteria
- type Tracer
Examples ¶
Constants ¶
const ( DefaultUpdateInterval = time.Second * 5 DefaultUpdateTimeout = time.Second )
Default values for cluster config
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AliveNodes ¶
AliveNodes of Cluster
type Cluster ¶
type Cluster struct {
// contains filtered or unexported fields
}
Cluster consists of number of 'nodes' of a single SQL database. Background goroutine periodically checks nodes and updates their status.
func NewCluster ¶
func NewCluster(nodes []Node, checker NodeChecker, opts ...ClusterOption) (*Cluster, error)
NewCluster constructs cluster object representing a single 'cluster' of SQL database. Close function must be called when cluster is not needed anymore.
Example ¶
package main import ( "context" "database/sql" "time" "golang.yandex/hasql" "golang.yandex/hasql/checkers" ) func main() { // cluster hosts hosts := []struct { Addr string Connstring string }{ { Addr: "host1.example.com", Connstring: "host=host1.example.com", }, { Addr: "host2.example.com", Connstring: "host=host2.example.com", }, { Addr: "host3.example.com", Connstring: "host=host3.example.com", }, } // Construct cluster nodes nodes := make([]hasql.Node, 0, len(hosts)) for _, host := range hosts { // Create database pools for each node db, err := sql.Open("pgx", host.Connstring) if err != nil { panic(err) } nodes = append(nodes, hasql.NewNode(host.Addr, db)) } // Use options to fine-tune cluster behavior opts := []hasql.ClusterOption{ hasql.WithUpdateInterval(2 * time.Second), // set custom update interval hasql.WithNodePicker(hasql.PickNodeRoundRobin()), // set desired nodes selection algorithm } // Create cluster handler c, err := hasql.NewCluster(nodes, checkers.PostgreSQL, opts...) if err != nil { panic(err) } defer func() { _ = c.Close() }() // close cluster when it is not needed ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Wait for current primary node, err := c.WaitForPrimary(ctx) if err != nil { panic(err) } // Wait for any alive standby node, err = c.WaitForStandby(ctx) if err != nil { panic(err) } // Wait for any alive node node, err = c.WaitForAlive(ctx) if err != nil { panic(err) } // Wait for secondary node if possible, primary otherwise node, err = c.WaitForNode(ctx, hasql.PreferStandby) if err != nil { panic(err) } // Retrieve current primary node = c.Primary() if node == nil { panic("no primary") } // Retrieve any alive standby node = c.Standby() if node == nil { panic("no standby") } // Retrieve any alive node node = c.Alive() if node == nil { panic("everything is dead") } // Retrieve primary node if possible, secondary otherwise node = c.Node(hasql.PreferPrimary) if node == nil { panic("no primary nor secondary") } // Retrieve secondary node if possible, primary otherwise node = c.Node(hasql.PreferStandby) if node == nil { panic("no primary nor secondary") } // Do something on retrieved node if err = node.DB().PingContext(ctx); err != nil { panic(err) } }
Output:
func (*Cluster) Err ¶ added in v1.1.1
Err returns the combined error including most recent errors for all nodes. This error is CollectedErrors or nil.
func (*Cluster) Node ¶
func (cl *Cluster) Node(criteria NodeStateCriteria) Node
Node returns cluster node with specified status.
func (*Cluster) Primary ¶
Primary returns first available node that is considered alive and is primary (able to execute write operations)
func (*Cluster) PrimaryPreferred ¶
PrimaryPreferred returns primary node if possible, standby otherwise
func (*Cluster) Standby ¶
Standby returns node that is considered alive and is standby (unable to execute write operations)
func (*Cluster) StandbyPreferred ¶
StandbyPreferred returns standby node if possible, primary otherwise
func (*Cluster) WaitForAlive ¶
WaitForAlive node to appear or until context is canceled
func (*Cluster) WaitForNode ¶
WaitForNode with specified status to appear or until context is canceled
func (*Cluster) WaitForPrimary ¶
WaitForPrimary node to appear or until context is canceled
func (*Cluster) WaitForPrimaryPreferred ¶
WaitForPrimaryPreferred node to appear or until context is canceled
func (*Cluster) WaitForStandby ¶
WaitForStandby node to appear or until context is canceled
type ClusterOption ¶
type ClusterOption func(*Cluster)
ClusterOption is a functional option type for Cluster constructor
func WithNodePicker ¶
func WithNodePicker(picker NodePicker) ClusterOption
WithNodePicker sets algorithm for node selection (e.g. random, round robin etc)
func WithTracer ¶
func WithTracer(tracer Tracer) ClusterOption
WithTracer sets tracer for actions happening in the background
func WithUpdateInterval ¶
func WithUpdateInterval(d time.Duration) ClusterOption
WithUpdateInterval sets interval between cluster node updates
func WithUpdateTimeout ¶
func WithUpdateTimeout(d time.Duration) ClusterOption
WithUpdateTimeout sets ping timeout for update of each node in cluster
type CollectedErrors ¶ added in v1.1.1
type CollectedErrors struct {
Errors []NodeError
}
CollectedErrors are errors collected when checking node statuses
func (*CollectedErrors) Error ¶ added in v1.1.1
func (e *CollectedErrors) Error() string
type NodeChecker ¶
NodeChecker is a signature for functions that check if specific node is alive and is primary. Returns true for primary and false if not. If error is returned, node is considered dead. Check function can be used to perform a query returning single boolean value that signals if node is primary or not.
type NodeError ¶ added in v1.1.1
NodeError is error that background goroutine got while check given node
type NodePicker ¶
NodePicker is a signature for functions that determine how to pick single node from set of nodes. Nodes passed to the picker function are sorted according to latency (from lowest to greatest).
func PickNodeClosest ¶ added in v1.0.0
func PickNodeClosest() NodePicker
PickNodeClosest returns node with least latency
func PickNodeRandom ¶
func PickNodeRandom() NodePicker
PickNodeRandom returns random node from nodes set
func PickNodeRoundRobin ¶
func PickNodeRoundRobin() NodePicker
PickNodeRoundRobin returns next node based on Round Robin algorithm
type NodeStateCriteria ¶
type NodeStateCriteria int
NodeStateCriteria for choosing a node
const ( // Alive for choosing any alive node Alive NodeStateCriteria = iota + 1 // Primary for choosing primary node Primary // Standby for choosing standby node Standby // PreferPrimary for choosing primary or any alive node PreferPrimary // PreferStandby for choosing standby or any alive node PreferStandby )
type Tracer ¶
type Tracer struct { // UpdateNodes is called when before updating nodes status. UpdateNodes func() // UpdatedNodes is called after all nodes are updated. The nodes is a list of currently alive nodes. UpdatedNodes func(nodes AliveNodes) // NodeDead is called when it is determined that specified node is dead. NodeDead func(node Node, err error) // NodeAlive is called when it is determined that specified node is alive. NodeAlive func(node Node) // NotifiedWaiters is called when all callers of 'WaitFor*' functions have been notified. NotifiedWaiters func() }
Tracer is a set of hooks to run at various stages of background nodes status update. Any particular hook may be nil. Functions may be called concurrently from different goroutines.
Example ¶
package main import ( "context" "database/sql" "fmt" "time" "golang.yandex/hasql" "golang.yandex/hasql/checkers" ) func main() { const hostname = "host=host1.example.com" db, err := sql.Open("pgx", "host="+hostname) if err != nil { panic(err) } nodes := []hasql.Node{hasql.NewNode(hostname, db)} tracer := hasql.Tracer{ UpdateNodes: func() { fmt.Println("Started updating nodes") }, UpdatedNodes: func(nodes hasql.AliveNodes) { fmt.Printf("Finished updating nodes: %+v\n", nodes) }, NodeDead: func(node hasql.Node, err error) { fmt.Printf("Node %q is dead: %s", node, err) }, NodeAlive: func(node hasql.Node) { fmt.Printf("Node %q is alive", node) }, NotifiedWaiters: func() { fmt.Println("Notified all waiters") }, } c, err := hasql.NewCluster(nodes, checkers.PostgreSQL, hasql.WithTracer(tracer)) if err != nil { panic(err) } defer func() { _ = c.Close() }() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() _, err = c.WaitForPrimary(ctx) if err != nil { panic(err) } }
Output: