Skip to main content

Async Python client for etcd v3 (grpc.aio, Python 3.11+)

Project description

etcd3aio

Async Python client for etcd v3 using grpc.aio.

CI PyPI Python 3.11+ License: MIT

Features

  • Thin facade over the etcd v3 gRPC API — no hidden magic
  • Async-first: all I/O via grpc.aio, never blocks the event loop
  • Strong typing: fully annotated, py.typed marker, satisfies pyright
  • Automatic retry with exponential backoff for transient errors
  • Watch streams with automatic reconnection
  • Distributed lock and leader election primitives
  • Background lease keep-alive and token refresh context managers

Requirements

  • Python 3.11+
  • etcd v3.5+ tested against v3.6 (see Local cluster to run one locally)

Installation

pip install etcd3aio

Quick Start

import asyncio
from etcd3aio import Etcd3Client, EtcdConnectionError

async def main() -> None:
    try:
        async with Etcd3Client(['localhost:2379']) as client:
            await client.ping()

            # Key-value
            await client.kv.put('myapp/greeting', 'hello')
            resp = await client.kv.get('myapp/greeting')
            print(resp.kvs[0].value.decode())  # hello

            # Distributed lock
            async with client.lock('myapp/resource'):
                print('acquired exclusive section')

            # Leader election
            async with client.election('myapp/leader', value=b'node-1') as e:
                leader = await e.leader()
                print(f'leader: {leader.kvs[0].value.decode()}')
    except EtcdConnectionError:
        print('could not connect to etcd')
        raise SystemExit(1)

asyncio.run(main())

Error Handling

All etcd errors inherit from EtcdError. The table below maps each exception to the underlying gRPC status code and the typical recovery action.

from etcd3aio import (
    EtcdError,
    EtcdConnectionError,
    EtcdTransientError,
    EtcdUnauthenticatedError,
    EtcdPermissionDeniedError,
)

try:
    await client.kv.put('key', 'value')
except EtcdConnectionError:
    # UNAVAILABLE — endpoint unreachable after all retry attempts
    # Action: check cluster health, verify endpoints
    ...
except EtcdTransientError:
    # DEADLINE_EXCEEDED — operation timed out after all retry attempts
    # Action: retry with backoff or increase the deadline
    ...
except EtcdUnauthenticatedError:
    # UNAUTHENTICATED — token missing, expired, or invalid
    # Action: re-authenticate and set a new token
    ...
except EtcdPermissionDeniedError:
    # PERMISSION_DENIED — authenticated user lacks the required role/permission
    # Action: review RBAC grants for this user
    ...
except EtcdError:
    # Catch-all for any other etcd-related error
    ...

Transient errors (UNAVAILABLE, DEADLINE_EXCEEDED) are retried automatically with exponential backoff (up to 3 attempts, 0.05 s → 1.0 s). Exceptions are only raised after all retry attempts are exhausted.

Local cluster (Docker)

docker compose -f docker/compose.yaml up -d

This starts two independent clusters:

Cluster Ports Transport
etcd1 / etcd2 / etcd3 2379, 3379, 4379 Plain TCP (no TLS)
etcdtls1 / etcdtls2 / etcdtls3 5379, 6379, 7379 Mutual TLS (mTLS)

Generating TLS certificates

The mTLS cluster requires certificate files in docker/. To regenerate them:

bash docker/gen-certs.sh

This creates server-ca.crt, client-cert.crt, client-key.key, and peer certificate pairs — all with the correct Subject Alternative Names for the TLS cluster nodes.

Connecting to the TLS cluster

Three certificate files are required — obtain them from your etcd administrator or generate them with gen-certs.sh for local development:

File Purpose Etcd3Client parameter
server-ca.crt CA that signed the server certificate ca_cert
client-cert.crt Client certificate presented during the mTLS handshake cert_chain
client-key.key Private key for the client certificate cert_key

Pass the file contents as bytes directly to the client constructor:

from pathlib import Path
from etcd3aio import Etcd3Client

certs = Path('docker')  # adjust to your certificate directory

async with Etcd3Client(
    ['localhost:5379', 'localhost:6379', 'localhost:7379'],
    ca_cert=    (certs / 'server-ca.crt').read_bytes(),
    cert_chain= (certs / 'client-cert.crt').read_bytes(),
    cert_key=   (certs / 'client-key.key').read_bytes(),
    tls_server_name='localhost',  # required for multi-endpoint TLS — see MODULES.md
) as client:
    await client.ping()

tls_server_name is required when connecting to multiple endpoints. The gRPC ipv4: round-robin scheme encodes all addresses as a comma-separated string and cannot derive a hostname for TLS verification. Set it to a DNS name present in the server certificate's Subject Alternative Names (SANs).

Documentation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

etcd3aio-0.3.0.tar.gz (52.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

etcd3aio-0.3.0-py3-none-any.whl (61.0 kB view details)

Uploaded Python 3

File details

Details for the file etcd3aio-0.3.0.tar.gz.

File metadata

  • Download URL: etcd3aio-0.3.0.tar.gz
  • Upload date:
  • Size: 52.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for etcd3aio-0.3.0.tar.gz
Algorithm Hash digest
SHA256 1d4f664a6d2f22e9331d4150e0eabf1dc44b4b2dc85792e6fcab60c0a9ea278b
MD5 fdc3b613fe8c0430253c6d759872b68b
BLAKE2b-256 41808aba9731ed9e4b3c0a586d404d722ba02d2c4f36002c7fca88770f1fe77f

See more details on using hashes here.

Provenance

The following attestation bundles were made for etcd3aio-0.3.0.tar.gz:

Publisher: publish.yml on danielsabatini/etcd3aio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file etcd3aio-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: etcd3aio-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 61.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for etcd3aio-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 da2221e1a24bc162b54ad4fa60264bbba1fd3f1e3494f5630328d2c8a0c276a6
MD5 9eb9900ad294b5d1d35b8d6ae4675216
BLAKE2b-256 0e630d774813e09769a843ef5781a47d80cad53e7b039672110e1df27bdea9d1

See more details on using hashes here.

Provenance

The following attestation bundles were made for etcd3aio-0.3.0-py3-none-any.whl:

Publisher: publish.yml on danielsabatini/etcd3aio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page