Documentation ¶
Overview ¶
Package leaderelection provides a simple to configure mechanism for electing a leader among processes.
There are two real entrypoints within this package: Config.Acquire() and WatchConfig.Watch(). Config.Acquire() is used for acquiring leadership, while `WatchConfig.Watch` is for observing leadership transitions and status.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SelfHostPorts ¶ added in v0.2.0
SelfHostPorts gets the global unicast addresses of the local execution environment and returns a slice of IP:Port which can be passed to Config.HostPort
Types ¶
type Config ¶
type Config struct { // OnElected is called when the local instance wins an election // The context is cancelled when the lock is lost. // The expirationTime argument will contain the expiration time and its // contents will be updated as the term expiration gets extended. // One should use the ValueInFuture method on TimeView to verify that // the lock is still held before doing anything that requires the // leader role. OnElected func(ctx context.Context, expirationTime *TimeView) // OnOusting is called when leadership is lost. OnOusting func(ctx context.Context) // LeaderChanged is called when another candidate becomes leader. LeaderChanged func(ctx context.Context, entry entry.RaceEntry) LeaderID string // HostPort is a slice of the system's unicast interface addresses to which clients should connect. // Optional, but recommended in general. // Required if used in combination with legrpc, so the RaceDecider has // a record of how to connect to the current leader. HostPort []string // Decider is the RaceDecider implementation in use Decider RaceDecider // TermLength indicates how long a leader is allowed to hold a // leadership role before it expires (if it's not extended) // This must be at least 2x MaxClockSkew (preferably more). TermLength time.Duration // Maximum expected clock-skew, so sleeps, time-bounds are adjusted to // take this into account. MaxClockSkew time.Duration // ConnectionParams should be used as a side-channel for // leader-election metadata for the legrpc package, e.g. we use it for // storing the GRPC ServiceConfig (or nothing). ConnectionParams []byte // Clock implementation to use when scheduling sleeps, renewals and comparing leader-terms. // The nil-value falls back to a sane default implementation that simply wraps // the `time` package's functions. Clock clocks.Clock }
Config defines the common fields of configs for various leaderelection backend implementations.
func (Config) Acquire ¶
Acquire blocks until the context expires or is cancelled.
Example ¶
ctx, cancel := context.WithCancel(context.Background()) defer cancel() d := memory.NewDecider() now := time.Date(2020, 5, 6, 0, 0, 0, 0, time.UTC) fc := fake.NewClock(now) tvLeaderIndicator := (*TimeView)(nil) electedCh := make(chan struct{}) c := Config{ Decider: d, HostPort: []string{"127.0.0.1:8080"}, LeaderID: "yabadabadoo", OnElected: func(ctx context.Context, tv *TimeView) { fmt.Printf("I won! Leader term expiration: %s; held: %t\n", tv.Get(), tv.ValueInFuture()) tvLeaderIndicator = tv close(electedCh) }, OnOusting: func(ctx context.Context) { // make sure we've already set `tvLeaderIndictor` before touching it <-electedCh fmt.Printf("I lost! Holding Lock: %t; expires: %s\n", // Note that ValueInFuture will return true // here because the clock is still within the // term. tvLeaderIndicator.ValueInFuture(), tvLeaderIndicator.Get()) }, LeaderChanged: func(ctx context.Context, entry entry.RaceEntry) { fmt.Printf("%q won\n", entry.LeaderID) }, TermLength: time.Minute * 30, MaxClockSkew: time.Second * 10, Clock: fc, } acquireCh := make(chan error, 1) go func() { acquireCh <- c.Acquire(ctx) }() fc.AwaitSleepers(1) <-electedCh fc.Advance(c.TermLength / 2) // Wait for the lease renewal to happen before cancelling (so the // output is predictable) fc.AwaitSleepers(1) cancel() // Acquire blocks until all callbacks return (there's an internal WaitGroup) <-acquireCh // advance past the end of the current term (after an extension) fc.Advance(c.TermLength + time.Minute) fmt.Printf("Still Leading: %t; expiry: %s; current time: %s\n", tvLeaderIndicator.ValueInFuture(), tvLeaderIndicator.Get(), fc.Now())
Output: I won! Leader term expiration: 2020-05-06 00:30:00 +0000 UTC; held: true I lost! Holding Lock: true; expires: 2020-05-06 00:45:00 +0000 UTC "" won Still Leading: false; expiry: 2020-05-06 00:45:00 +0000 UTC; current time: 2020-05-06 00:46:00 +0000 UTC
type FailedAcquisitionErr ¶
type FailedAcquisitionErr interface { error FailedAcquire() }
FailedAcquisitionErr types indicate that the error was non-fatal and most likely a result of someone else grabbing the lock before us
type RaceDecider ¶
type RaceDecider interface { // WriteEntry implementations should write the entry argument to // stable-storage in a transactional-way such that only one contender // wins per-election/term // The interface{} return value is a new token if the write succeeded. WriteEntry(ctx context.Context, entry *entry.RaceEntry) (entry.LeaderToken, error) // ReadCurrent should provide the latest version of RaceEntry available // and put any additional information needed to ensure transactional // behavior in the Token-field. ReadCurrent(ctx context.Context) (*entry.RaceEntry, error) }
RaceDecider is a storage backend that provides transactional semantics
type TimeView ¶
type TimeView struct {
// contains filtered or unexported fields
}
TimeView is a value containing an atomically updatable time.Time
func (*TimeView) Set ¶
Set sets the current value of the encapsulated timestamp Exported so clients can change the values in tests
func (*TimeView) ValueInFuture ¶
ValueInFuture compares the currently held timestamp against the current timestamp associated with the contained clock. (equivalent to still owning leadership as returned by Acquire)
type WatchConfig ¶
type WatchConfig struct { // Decider used to lookup the current leader Decider RaceDecider // Clock implementation to use when scheduling sleeps and comparing leader-terms. // The nil-value falls back to a sane default implementation that simply wraps // the `time` package's functions. Clock clocks.Clock }
WatchConfig configures the watcher
func (WatchConfig) Watch ¶
func (w WatchConfig) Watch(ctx context.Context, cb func(ctx context.Context, entry entry.RaceEntry)) error
Watch provides a way for an observer to watch for changes to the identity of the current leader
Example ¶
ctx, cancel := context.WithCancel(context.Background()) defer cancel() d := memory.NewDecider() now := time.Date(2020, 5, 6, 0, 0, 0, 0, time.UTC) fc := fake.NewClock(now) watchConfig := WatchConfig{ Decider: d, Clock: fc, } c, _ := d.ReadCurrent(ctx) d.WriteEntry(ctx, &entry.RaceEntry{ LeaderID: "fimbat", HostPort: []string{"test:80"}, TermExpiry: now.Add(time.Hour), ElectionNumber: c.ElectionNumber + 1, ConnectionParams: nil, Token: c.Token, }) ch := make(chan struct{}) go func() { defer close(ch) _ = watchConfig.Watch(ctx, func(ctx context.Context, e entry.RaceEntry) { fmt.Println(e.HostPort, e.TermExpiry) }) }() fc.AwaitSleepers(1) cancel() <-ch
Output: [test:80] 2020-05-06 01:00:00 +0000 UTC
Directories ¶
Path | Synopsis |
---|---|
Package gcs contains an implementation of RaceDecider (plus helpers) for using Google Cloud Storage as a backend in leader-election.
|
Package gcs contains an implementation of RaceDecider (plus helpers) for using Google Cloud Storage as a backend in leader-election. |
Package memory implements an in-memory variant of the Decider to allow for quick local/single-process testing
|
Package memory implements an in-memory variant of the Decider to allow for quick local/single-process testing |