moonsd service discovery

Backend · Redis

moonredis

A complete Redis client, and moonredis/sd: the contract carried by keys that expire. An endpoint is a key with a ttl; an instance that stops renewing removes itself, because that is what expiry is.

keymoonsd:{greeter}:10.0.0.11:12000
value{"host":"10.0.0.11","port":12000,"weight":2}
registerSET key value PX ttl
renewPEXPIRE key ttl
tokenthe key itself
lapsethe key expires, and nobody had to sweep it
i

What it is

A key is a registration

Redis already knows how to forget things on a schedule, so the registry borrows that instead of running a sweeper of its own. The endpoint is written as JSON under moonsd:{service}:{id} with a ttl, and renewing is PEXPIRE. The braces are a hash tag: a service's keys share a cluster slot, so a lookup of one service never fans out across the cluster.

ii

The lease

Three calls, no lease ids

01

register

SET key value PX ttl. The token in the lease is the key itself, so renewing and removing need nothing else.

02

renew

PEXPIRE key ttl. It answers zero when the key is already gone, which is the one case the contract calls Refused::Expired.

03

deregister

DEL key, and harmless when the key has already expired — the same command either way.

iii

The watcher

Expiry announces nothing, so look again

Keyspace notifications exist and are best effort: a client that subscribes to them can miss the event of a key expiring while it was disconnected, which is precisely the moment a registry matters. So watch reads the service again every poll milliseconds — a second by default — and reports a change only when the list differs.

The registry takes a lock around its own commands, because a shared connection answers one command at a time and a cancelled task must still read its reply. Give the registry a client of its own; the lock orders the registry's commands, not those of anything else on that connection.

prefix moonsd poll 1000 ms token the key verified against Redis 8, standalone, cluster and sentinel
iv

The client behind it

The whole client, not a discovery shim

sd is a small package on top of a full client: RESP2 and RESP3, the command families including the Redis 8 modules, pipelines and transactions, pub/sub with sharding, client-side caching, cluster routing, sentinel discovery, a pool, retries, TLS and ACL authentication. A service that already talks to Redis for its cache uses the same client for its registration.