Backend · etcd
A complete etcd client, and moonetcd/sd: the contract on keys
attached to leases. The key goes when the lease does, and the revision etcd stamps on
every write is where a watcher picks up.
What it is
etcd already has the two mechanisms a registry needs: keys that vanish with a lease, and a
monotonically increasing revision on every write. The registry puts
/moonsd/{service}/{id} on a granted lease and lets etcd do the
forgetting. A service name is escaped on the way into the key, so a prefix read of service
a cannot pick up service a/b.
The lease
lease().grant(seconds) then kv().put(key, value, lease=id).
A lease lasts whole seconds and the server enforces a minimum, so a millisecond ttl is
rounded up rather than down — rounding down would end the lease early.
One keep_alive round. etcd answers an acknowledgement with
no time left rather than an error when the lease is gone, and that is what becomes
Refused::Expired.
Revoking the lease takes every key on it with it, which is why the token can be a string in the contract and still be enough to clean up.
The watcher
The first snapshot is a range read; each later one is a watch from the last revision seen. A connection that drops, or a history that has been compacted past the revision, is answered by reading the whole service once and watching from there — the caller sees another snapshot and nothing else, which is the promise the watcher made.
The client behind it
sd sits on a client that speaks etcd's gRPC service and its JSON
gateway, over TLS with or without a client certificate. KV, watch, lease, cluster, auth,
maintenance, lock and election are all there, along with the concurrency helpers built on
them, because a service that elects a leader already has the client.