Documentation
¶
Overview ¶
election.go
Example ¶
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"github.com/OpexDevelop/go-failover"
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer cancel()
cluster, err := failover.Run(ctx, failover.Config{
Project: "myservice",
NodePriority: 1,
Strategy: failover.Priority,
RedisURL: os.Getenv("REDIS_URL"),
OnStart: func(ctx context.Context) error {
fmt.Println("I am the leader now!")
// Block until leadership is lost
<-ctx.Done()
fmt.Println("Leadership context cancelled, cleaning up...")
return nil
},
OnStop: func() {
fmt.Println("I lost leadership")
},
})
if err != nil {
panic(err)
}
defer cluster.Close()
cluster.Wait()
}
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FormatStats ¶
FormatStats returns a human-readable HTML string (suitable for Telegram).
Types ¶
type Cluster ¶
type Cluster struct {
// contains filtered or unexported fields
}
Cluster is a running failover instance.
func Run ¶
Run starts the failover loop. It connects to Redis, validates config, and begins leader election in a background goroutine. The returned Cluster is safe for concurrent use.
func (*Cluster) Close ¶
Close waits for the internal loop to finish and releases the Redis connection. Safe to call multiple times — subsequent calls return the same error as the first call. The context passed to Run must be cancelled before calling Close.
type Config ¶
type Config struct {
// Project is a unique name used as Redis key prefix. Required.
Project string
// NodeID uniquely identifies this node. Defaults to hostname.
NodeID string
// Priority of this node (lower = higher priority).
// Only meaningful with Strategy = Priority. Defaults to 1.
NodePriority int
// Strategy selects election mode. Default: Race.
Strategy Strategy
// RedisURL is the connection string for Redis.
// Ignored when RedisOptions is set.
RedisURL string
// RedisOptions allows full control over the Redis connection.
// When set, RedisURL is ignored.
RedisOptions *redis.Options
// TickInterval is how often the node checks state. Default: 500ms.
// A random jitter of ±20% is applied to each tick.
TickInterval time.Duration
// LeaseTTL is the leader key expiration. Default: 3s. Minimum: 100ms.
LeaseTTL time.Duration
// MaxDrift is max time without successful refresh before step-down.
// Default: LeaseTTL / 2.
MaxDrift time.Duration
// OnStart is called in a separate goroutine when this node becomes leader.
// The context is cancelled when leadership is lost — OnStart MUST return
// promptly when ctx.Done() fires. If OnStart returns a non-nil error,
// the node steps down immediately.
OnStart func(ctx context.Context) error
// OnStop is called when this node loses leadership, after OnStart returns.
// Must complete within 1 second or it is abandoned (goroutine leak).
OnStop func()
// Logger is an optional structured logger. If nil, slog.Default() is used.
Logger *slog.Logger
}
Config configures the failover election.
type Event ¶
type Event struct {
NodeID string `json:"node_id"`
Action string `json:"action"`
Timestamp time.Time `json:"timestamp"`
}
Event represents a recorded leadership event.
type LiveNode ¶
type LiveNode struct {
NodeID string `json:"node_id"`
Priority int `json:"priority"`
IsLeader bool `json:"is_leader"`
LastSeen time.Time `json:"last_seen"`
}
LiveNode represents a currently alive node.
type NodeInfo ¶
type NodeInfo struct {
NodeID string `json:"node_id"`
Priority int `json:"priority"`
Project string `json:"project"`
IsLeader bool `json:"is_leader"`
Revision int64 `json:"revision"`
}
NodeInfo contains information about the current node.