Documentation ¶
Overview ¶
Example ¶
To start the first node of a dqlite cluster for the first time, its network address should be specified using the app.WithAddress() option.
When the node is restarted a second time, the app.WithAddress() option might be omitted, since the node address will be persisted in the info.yaml file.
The very first node has always the same ID (dqlite.BootstrapID).
package main import ( "fmt" "io/ioutil" "os" "github.com/ardhipoetra/go-dqlite/app" ) func main() { dir, err := ioutil.TempDir("", "dqlite-app-example-") if err != nil { return } defer os.RemoveAll(dir) node, err := app.New(dir, app.WithAddress("127.0.0.1:9001")) if err != nil { return } fmt.Printf("0x%x %s\n", node.ID(), node.Address())
Output: 0x2dc171858c3155be 127.0.0.1:9001 0x2dc171858c3155be 127.0.0.1:9001
Index ¶
- func SimpleDialTLSConfig(cert tls.Certificate, pool *x509.CertPool) *tls.Config
- func SimpleListenTLSConfig(cert tls.Certificate, pool *x509.CertPool) *tls.Config
- func SimpleTLSConfig(cert tls.Certificate, pool *x509.CertPool) (*tls.Config, *tls.Config)
- type App
- func (a *App) Address() string
- func (a *App) Client(ctx context.Context) (*client.Client, error)
- func (a *App) Close() error
- func (a *App) Driver() string
- func (a *App) Handover(ctx context.Context) error
- func (a *App) ID() uint64
- func (a *App) Leader(ctx context.Context) (*client.Client, error)
- func (a *App) Open(ctx context.Context, database string) (*sql.DB, error)
- func (a *App) Ready(ctx context.Context) error
- type Option
- func WithAddress(address string) Option
- func WithCluster(cluster []string) Option
- func WithFailureDomain(code uint64) Option
- func WithLogFunc(log client.LogFunc) Option
- func WithNetworkLatency(latency time.Duration) Option
- func WithRolesAdjustmentFrequency(frequency time.Duration) Option
- func WithStandBys(n int) Option
- func WithTLS(listen *tls.Config, dial *tls.Config) Option
- func WithVoters(n int) Option
- type RolesChanges
- type RolesConfig
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SimpleDialTLSConfig ¶
SimpleDialTLSConfig returns a client-side TLS configuration with sane defaults (e.g. TLS version, ciphers and mutual authentication).
The cert parameter must be a public/private key pair, typically loaded from disk using tls.LoadX509KeyPair().
The pool parameter can be used to specify a custom signing CA (e.g. for self-signed certificates).
When server and client both use the same certificate, the same key pair and pool should be passed to SimpleListenTLSConfig() in order to generate the server-side config.
The returned config can be used as "client" parameter for the WithTLS App option, or as "config" parameter for the client.DialFuncWithTLS() helper.
func SimpleListenTLSConfig ¶
SimpleListenTLSConfig returns a server-side TLS configuration with sane defaults (e.g. TLS version, ciphers and mutual authentication).
The cert parameter must be a public/private key pair, typically loaded from disk using tls.LoadX509KeyPair().
The pool parameter can be used to specify a custom signing CA (e.g. for self-signed certificates).
When server and client both use the same certificate, the same key pair and pool should be passed to SimpleDialTLSConfig() in order to generate the client-side config.
The returned config can be used as "listen" parameter for the WithTLS option.
func SimpleTLSConfig ¶
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
App is a high-level helper for initializing a typical dqlite-based Go application.
It takes care of starting a dqlite node and registering a dqlite Go SQL driver.
func (*App) Handover ¶ added in v1.8.1
Handover transfers all responsibilities for this node (such has leadership and voting rights) to another node, if one is available.
This method should always be called before invoking Close(), in order to gracefully shutdown a node.
func (*App) Ready ¶ added in v1.8.1
Ready can be used to wait for a node to complete some initial tasks that are initiated at startup. For example a brand new node will attempt to join the cluster, a restarted node will check if it should assume some particular role, etc.
If this method returns without error it means that those initial tasks have succeeded and follow-up operations like Open() are more likely to succeeed quickly.
type Option ¶
type Option func(*options)
Option can be used to tweak app parameters.
func WithAddress ¶
WithAddress sets the network address of the application node.
Other application nodes must be able to connect to this application node using the given address.
If the application node is not the first one in the cluster, the address must match the value that was passed to the App.Add() method upon registration.
If not given the first non-loopback IP address of any of the system network interfaces will be used, with port 9000.
The address must be stable across application restarts.
func WithCluster ¶
WithCluster must be used when starting a newly added application node for the first time.
It should contain the addresses of one or more applications nodes which are already part of the cluster.
Example ¶
After starting the very first node, a second node can be started by passing the address of the first node using the app.WithCluster() option.
In general additional nodes can be started by specifying one or more addresses of existing nodes using the app.Cluster() option.
When the node is restarted a second time, the app.WithCluster() option might be omitted, since the node has already joined the cluster.
Each additional node will be automatically assigned a unique ID.
package main import ( "fmt" "io/ioutil" "os" "github.com/ardhipoetra/go-dqlite/app" ) func main() { dir1, err := ioutil.TempDir("", "dqlite-app-example-") if err != nil { return } defer os.RemoveAll(dir1) dir2, err := ioutil.TempDir("", "dqlite-app-example-") if err != nil { return } defer os.RemoveAll(dir2) dir3, err := ioutil.TempDir("", "dqlite-app-example-") if err != nil { return } defer os.RemoveAll(dir3) node1, err := app.New(dir1, app.WithAddress("127.0.0.1:9001")) if err != nil { return } defer node1.Close() node2, err := app.New(dir2, app.WithAddress("127.0.0.1:9002"), app.WithCluster([]string{"127.0.0.1:9001"})) if err != nil { return } defer node2.Close() node3, err := app.New(dir3, app.WithAddress("127.0.0.1:9003"), app.WithCluster([]string{"127.0.0.1:9001"})) if err != nil { return } fmt.Println(node1.ID() != node2.ID(), node1.ID() != node3.ID(), node2.ID() != node3.ID())
Output:
func WithFailureDomain ¶ added in v1.8.1
WithFailureDomain sets the node's failure domain.
Failure domains are taken into account when deciding which nodes to promote to Voter or StandBy when needed.
func WithLogFunc ¶
WithLogFunc sets a custom log function.
func WithNetworkLatency ¶ added in v1.8.1
WithNetworkLatency sets the average one-way network latency.
func WithRolesAdjustmentFrequency ¶ added in v1.8.1
WithRolesAdjustmentFrequency sets the frequency at which the current cluster leader will check if the roles of the various nodes in the cluster matches the desired setup and perform promotions/demotions to adjust the situation if needed.
The default is 30 seconds.
func WithStandBys ¶ added in v1.8.1
WithStandBys sets the number of nodes in the cluster that should have the StandBy role.
When a new node is added to the cluster or it is started again after a shutdown it will be assigned the StandBy role in case there are already enough online voters, but the current number of stand-bys is below n.
Similarly when a node with the StandBy role is shutdown gracefully by calling the Handover() method, it will try to transfer its StandBy role to another non-StandBy node, if one is available.
All App instances in a cluster must be created with the same WithStandBys setting.
The given value must be an odd number.
The default value is 3.
func WithTLS ¶
WithTLS enables TLS encryption of network traffic.
The "listen" parameter must hold the TLS configuration to use when accepting incoming connections clients or application nodes.
The "dial" parameter must hold the TLS configuration to use when establishing outgoing connections to other application nodes.
func WithVoters ¶ added in v1.8.1
WithVoters sets the number of nodes in the cluster that should have the Voter role.
When a new node is added to the cluster or it is started again after a shutdown it will be assigned the Voter role in case the current number of voters is below n.
Similarly when a node with the Voter role is shutdown gracefully by calling the Handover() method, it will try to transfer its Voter role to another non-Voter node, if one is available.
All App instances in a cluster must be created with the same WithVoters setting.
The given value must be an odd number greater than one.
The default value is 3.
type RolesChanges ¶ added in v1.8.1
type RolesChanges struct { // Algorithm configuration. Config RolesConfig // Current state of the cluster. Each node in the cluster must be // present as a key in the map, and its value should be its associated // failure domain and weight metadata or nil if the node is currently // offline. State map[client.NodeInfo]*client.NodeMetadata }
RolesChanges implements an algorithm to take decisions about which node should have which role in a cluster.
You normally don't need to use this data structure since it's already transparently wired into the high-level App object. However this is exposed for users who don't want to use the high-level App object but still want to implement the same roles management algorithm.
func (*RolesChanges) Adjust ¶ added in v1.8.1
Adjust decides if there should be changes in the current roles.
Return the role that should be assigned and a list of candidates that should assume it, in order of preference.
func (*RolesChanges) Assume ¶ added in v1.8.1
func (c *RolesChanges) Assume(id uint64) client.NodeRole
Assume decides if a node should assume a different role than the one it currently has. It should normally be run at node startup, where the algorithm might decide that the node should assume the Voter or Stand-By role in case there's a shortage of them.
Return -1 in case no role change is needed.
func (*RolesChanges) Handover ¶ added in v1.8.1
Handover decides if a node should transfer its current role to another node. This is typically run when the node is shutting down and is hence going to be offline soon.
Return the role that should be handed over and list of candidates that should receive it, in order of preference.
type RolesConfig ¶ added in v1.8.1
type RolesConfig struct { Voters int // Target number of voters, 3 by default. StandBys int // Target number of stand-bys, 3 by default. }
RolesConfig can be used to tweak the algorithm implemented by RolesChanges.