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 ¶
- type Client
- func (c *Client) Campaign(ctx context.Context, key, identity string, ttl time.Duration) (*Election, error)
- func (c *Client) Close() error
- func (c *Client) ConfigSource(name string) config.Source
- func (c *Client) Discover(ctx context.Context, name string) ([]Descriptor, error)
- func (c *Client) Lock(ctx context.Context, key string, ttl time.Duration) (*Lock, error)
- func (c *Client) Prefix() string
- func (c *Client) Raw() *clientv3.Client
- func (c *Client) Register(ctx context.Context, info Descriptor, ttl time.Duration) (*Registration, error)
- func (c *Client) TryLock(ctx context.Context, key string, ttl time.Duration) (*Lock, error)
- func (c *Client) WatchService(ctx context.Context, name string, handler func(ServiceEvent)) (func(), error)
- type Config
- type Descriptor
- type Election
- type Lock
- type Registration
- type ServiceEvent
- type ServiceEventType
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 ¶
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) ConfigSource ¶
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 ¶
Discover returns a snapshot of all currently registered instances of the given service name.
func (*Client) Lock ¶
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) Raw ¶
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 ¶
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.
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) Leader ¶
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).
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.
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.