etcd

package
v1.10.3 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2026 License: BSD-3-Clause Imports: 12 Imported by: 0

Documentation

Overview

Package etcd provides a thin, opinionated wrapper around the official etcd v3 client tailored for go-core applications.

The package bundles four capabilities on top of a single *clientv3.Client:

  • A config.Source implementation that lets the config package read, write and watch configuration values stored in etcd, either as the sole source (etcd-only mode) or as an overlay on top of a local YAML file (hybrid mode).
  • Service registration with TTL leases and automatic keep-alive plus graceful deregistration.
  • Service discovery: snapshot queries and change-streaming watches over registered services.
  • Distributed locks and leader election via the etcd concurrency primitives.

All capabilities share a single Client and use a caller-supplied key prefix (Config.Prefix) so multiple independent applications can coexist in the same etcd cluster. Endpoints, TLS and credentials must be supplied by the application implementor; no flags or environment lookups are performed by this package.

Example - distributed config (etcd-only):

cli, err := etcd.New(ctx, etcd.Config{
    Endpoints: []string{"localhost:2379"},
    Prefix:    "/apps/myapp",
})
if err != nil {
    return err
}
defer cli.Close()

config.Manager().WithName("myapp").WithSource(cli.ConfigSource("myapp"))
if err := config.Register(cfg); err != nil { return err }
if err := config.Read(); err != nil { return err }
_ = config.StartWatch(ctx)

Example - hybrid config (file base, etcd overlay):

config.Manager().WithName("myapp").WithOverlay(cli.ConfigSource("myapp"))
_ = config.Read()
_ = config.StartWatch(ctx)

Example - service registration and discovery:

reg, err := cli.Register(ctx, etcd.ServiceInfo{
    Name:    "billing",
    ID:      "billing-1",
    Address: "10.0.0.5:8080",
}, 15*time.Second)
defer reg.Deregister(context.Background())

endpoints, err := cli.Discover(ctx, "billing")
cancel, err := cli.WatchService(ctx, "billing", func(ev etcd.ServiceEvent) {
    // ...
})
defer cancel()

Example - distributed lock and election:

lock, err := cli.Lock(ctx, "/jobs/cleanup", 10*time.Second)
defer lock.Unlock(ctx)

el, err := cli.Campaign(ctx, "/leader/scheduler", "node-1", 10*time.Second)
defer el.Resign(context.Background())

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client wraps a *clientv3.Client together with the resolved key prefix and a lifecycle context shared by all helpers in this package.

func New

func New(ctx context.Context, cfg Config) (*Client, error)

New dials etcd using the provided configuration and returns a Client. The caller owns the returned client and must invoke Close to release the underlying resources.

func (*Client) Campaign

func (c *Client) Campaign(ctx context.Context, key, identity string, ttl time.Duration) (*Election, error)

Campaign begins campaigning for leadership of the given election key. The returned Election immediately attempts to become leader; callers can use Leader, Observe and Resign to interact with it. Campaign blocks until either leadership is acquired, the context is cancelled, or the underlying session is lost.

identity is the value advertised to observers; it is typically a hostname, instance id, or any unique string callers want to expose.

func (*Client) Close

func (c *Client) Close() error

Close releases the underlying etcd client and any associated resources.

func (*Client) ConfigSource

func (c *Client) ConfigSource(name string) config.Source

ConfigSource returns a config.Source that reads, writes and watches the configuration named "name" from etcd. Plug the returned source into the config package via config.Manager().WithSource(...) for etcd-only mode or config.Manager().WithOverlay(...) for a hybrid setup.

func (*Client) Discover

func (c *Client) Discover(ctx context.Context, name string) ([]Descriptor, error)

Discover returns a snapshot of all currently registered instances of the given service name.

func (*Client) Lock

func (c *Client) Lock(ctx context.Context, key string, ttl time.Duration) (*Lock, error)

Lock acquires a distributed mutex at the given key (resolved under the client's configured prefix) and returns a handle the caller can use to release it. The call blocks until the lock is acquired or the context is cancelled.

A zero ttl falls back to the package default (30 seconds). The minimum effective TTL accepted by etcd concurrency sessions is one second.

func (*Client) Prefix

func (c *Client) Prefix() string

Prefix returns the configured key prefix.

func (*Client) Raw

func (c *Client) Raw() *clientv3.Client

Raw returns the underlying *clientv3.Client for advanced usage that this package does not yet wrap. The returned client is owned by Client; do not call Close on it directly.

func (*Client) Register

func (c *Client) Register(ctx context.Context, info Descriptor, ttl time.Duration) (*Registration, error)

Register stores the service info in etcd under a freshly granted lease and starts a background keep-alive routine. The lease is automatically revoked when Deregister is called or when the parent context is cancelled.

A zero ttl falls back to the package default (15 seconds). The minimum effective TTL accepted by etcd is one second; smaller values are raised.

func (*Client) TryLock

func (c *Client) TryLock(ctx context.Context, key string, ttl time.Duration) (*Lock, error)

TryLock attempts to acquire the lock without blocking. It returns (nil, nil) when the lock is currently held by another holder.

func (*Client) WatchService

func (c *Client) WatchService(ctx context.Context, name string, handler func(ServiceEvent)) (func(), error)

WatchService subscribes to changes for the given service name. The handler is invoked from a single goroutine; long-running work should be dispatched elsewhere. The returned cancel function stops the watch goroutine.

type Config

type Config struct {
	// Endpoints is the list of etcd endpoints (e.g. "host:2379"). At least
	// one endpoint must be provided.
	Endpoints []string
	// Username is the optional username used for authentication.
	Username string
	// Password is the optional password used for authentication.
	Password string
	// DialTimeout is the maximum time to wait for an initial connection.
	// When zero, a sane default (5 seconds) is used.
	DialTimeout time.Duration
	// TLS, when set, enables TLS using the provided configuration.
	TLS *tls.Config
	// Prefix is the key namespace under which all keys written by this
	// client live. It is prepended to every key used by ConfigSource,
	// Register, Discover, Lock, and Campaign. Defaults to "/go-core".
	Prefix string
	// AutoSyncInterval, when non-zero, enables periodic endpoint
	// auto-sync against the etcd cluster.
	AutoSyncInterval time.Duration
}

Config holds the connection parameters for an etcd client.

func (*Config) Validate

func (c *Config) Validate() error

Validate ensures the configuration is sufficient for dialing etcd.

type Descriptor

type Descriptor struct {
	ID       string            `json:"id"`
	Name     string            `json:"name"`
	Address  string            `json:"address"`
	Metadata map[string]string `json:"metadata,omitempty"`
}

Descriptor describes a single service instance registered in etcd. Name groups related instances; ID uniquely identifies one instance within a name. Address is the dial target (typically host:port). Metadata holds arbitrary string tags such as version, region or capabilities.

func (Descriptor) Validate

func (s Descriptor) Validate() error

Validate ensures the service information is sufficient for registration.

type Election

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

Election represents an ongoing leader election. The election runs in the background until Resign is called or the underlying session is lost.

func (*Election) Done

func (e *Election) Done() <-chan struct{}

Done returns a channel closed when the underlying session is lost.

func (*Election) Identity

func (e *Election) Identity() string

Identity returns the value advertised by this campaigner.

func (*Election) Key

func (e *Election) Key() string

Key returns the fully qualified election key.

func (*Election) Leader

func (e *Election) Leader(ctx context.Context) (string, error)

Leader returns the identity of the current leader of this election. An empty string with no error indicates the election currently has no leader (e.g. all participants resigned).

func (*Election) Observe

func (e *Election) Observe(ctx context.Context) <-chan string

Observe returns a channel that emits the identity of the current leader every time it changes. The channel is closed when ctx is cancelled or the underlying session is lost.

func (*Election) Resign

func (e *Election) Resign(ctx context.Context) error

Resign relinquishes leadership (if held) and closes the underlying session. After Resign the Election must not be used again.

type Lock

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

Lock represents an acquired distributed mutex. The underlying etcd session keeps a lease alive for the lifetime of the lock; if the holding process dies, the lock is released automatically once the lease expires.

func (*Lock) Done

func (l *Lock) Done() <-chan struct{}

Done returns a channel closed when the underlying session is lost (for example because the lease expired due to a network partition). Callers holding work-impacting locks should monitor this channel and abort.

func (*Lock) Key

func (l *Lock) Key() string

Key returns the fully qualified key the lock is held on.

func (*Lock) Unlock

func (l *Lock) Unlock(ctx context.Context) error

Unlock releases the lock and closes the underlying session.

type Registration

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

Registration represents an active service registration. It keeps the associated etcd lease alive in the background until Deregister is called or the context used to create it is cancelled.

func (*Registration) Deregister

func (r *Registration) Deregister(ctx context.Context) error

Deregister revokes the etcd lease, deletes the registration key and stops the background keep-alive routine. It is safe to call more than once; subsequent calls return the result of the first call.

func (*Registration) Info

func (r *Registration) Info() Descriptor

Info returns the service info backing this registration.

func (*Registration) LeaseID

func (r *Registration) LeaseID() clientv3.LeaseID

LeaseID returns the etcd lease id underpinning this registration.

type ServiceEvent

type ServiceEvent struct {
	Type ServiceEventType
	Info Descriptor
}

ServiceEvent describes a single change in the service registry.

type ServiceEventType

type ServiceEventType int

ServiceEventType enumerates the kinds of service-registry change events.

const (
	// ServiceAdded indicates a new service instance was registered.
	ServiceAdded ServiceEventType = iota + 1
	// ServiceModified indicates an existing service instance was updated.
	ServiceModified
	// ServiceRemoved indicates a service instance was deregistered or its
	// lease expired.
	ServiceRemoved
)

func (ServiceEventType) String

func (t ServiceEventType) String() string

String returns a human-readable name for the event type.

Jump to

Keyboard shortcuts

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