Skip to content

Recipes

Each recipe is a coordination pattern built from etcd's primitives — leases, watches, and atomic transactions. They share a lifecycle and a failure model, both described in Core concepts.

The catalog

Package Recipes
lock DistributedMutex, DistributedReadWriteLock, DistributedSemaphore
election LeaderSelector, LeaderLatch, LeaderObserver, Participant
barrier DistributedBarrier, DistributedBarrierWithCount, DistributedDoubleBarrier
queue DistributedQueue, DistributedPriorityQueue, DistributedWorkQueue, TypedDistributedQueue<T>, TypedDistributedPriorityQueue<T>
cache NodeCache<T>, PathChildrenCache, TypedPathChildrenCache<T>
counter DistributedAtomicLong
discovery ServiceDiscovery, ServiceRegistry, ServiceCache, ServiceProvider, ServiceInstance, ProviderStrategy
keyvalue TransientKeyValue, TypedTransientKeyValue<T>
common Kotlin extensions over jetcd; EtcdCodec<T>
coroutines Suspending twins, Flow event surfaces

Choosing one

I need one process to do this at a time. A DistributedMutex if it is a short critical section around a specific resource. A LeaderLatch if it is an ongoing role — a scheduler, a compactor — that one instance should hold for as long as it stays healthy. The difference is duration and intent: a lock guards a section, a leader owns a job.

I need at most N at a time. DistributedSemaphore.

Many readers, occasional writer. DistributedReadWriteLock.

Work must be done once, and survive a worker crash. DistributedWorkQueue — at-least-once with visibility timeouts and dead letters. Not DistributedQueue, which drops the item on the floor if a consumer dies holding it.

Fan work out, order matters, losses tolerable. DistributedQueue or DistributedPriorityQueue.

Everyone waits until everyone is ready. Barriers — simple for a gate someone opens, counted for an N-party rendezvous, double for enter-and-leave phase sync.

Read a value that changes, without hammering etcd. NodeCache<T> for one key, PathChildrenCache for a prefix. Both keep a local view current with a watch.

Find the instances of a service. Service discovery — with ServiceProvider if you want client-side load balancing and error ejection too.

Count something across processes. DistributedAtomicLong.

Advertise something that disappears if my process dies. TransientKeyValue.

What they share

  • Constructors do no I/O. Work happens in start() or on first use.
  • Closeable. close() is idempotent; most take use { }.
  • withXxx { }. Most have a scoped function that starts and closes for you.
  • Failures surface, they don't throw from worker threads. exceptions, listeners, and connectionState. See Core concepts.
  • Holds can be lost. See Leases and loss.
  • Typed variants exist for queues, caches and key/values via EtcdCodec<T>.
  • Suspending twins exist for nearly everything. See Coroutines.
  • They are Java-usable. See the Java guide.

Composing them

The recipes are built on the same Kotlin extensions over jetcd that you have, and they never hide the Client. Mixing a recipe with a raw transaction against your own keys is normal and expected, not a workaround.

The EtcdRecipes facade is a convenience factory for the common ones if you would rather not construct each type by hand.