API reference
Exports of @sigx/actors-redis v0.11.0.
redisCluster(options)
Returns ClusterProviders — membership and directory together. The common case.
cluster({ providers: redisCluster({ client }), advertise, secret });
interface RedisClusterOptions {
client?: RedisClient; // an ioredis instance, used with its own options
url?: string; // …or a URL to construct one, with enableAutoPipelining: true
namespace?: string; // 'sigx'
heartbeatMs?: number; // 5000
ttlMs?: number; // 15000
pollMs?: number; // 5000
}
Call it once per host — each call returns that host's own membership handle.
redisMembership(client, options?)
Membership alone: TTL heartbeats, a polled view with pub/sub push, and self-fencing when this
host cannot renew past ttlMs.
redisDirectory(client, options?)
The single-activation claim directory. Options: { namespace?: string }.
Pairs with any membership provider — notably
k8sMembership().
redisStorage(options)
An ActorStorage with etag compare-and-set.
defineActorApp({ storage: redisStorage({ client, namespace: 'sigx' }) });
interface RedisStorageOptions {
client?: RedisClient; // used with its own options
url?: string; // constructs a client with enableAutoPipelining: true
namespace?: string; // 'sigx' — share it with the cluster providers
}
Etags are client-minted UUIDs. save, clear and
appendText compare-and-set atomically in
Redis via Lua, registered as EVALSHA commands because save is the hot path, and throw the
branded ActorStorageConflict on mismatch — which the runtime turns into discard-and-reload.
An append pushes one entry onto the record's log LIST; a full save or a clear deletes it in
the same script.
With url, the package constructs its own client with enableAutoPipelining: true, so a
host's same-tick saves coalesce into fewer socket writes. Pass client to own the options.
redisReminders(options)
An ActorReminders on a due-time-indexed sorted set, passed as reminders:.
defineActorApp({ storage: redisStorage({ client }), reminders: redisReminders({ client }) });
interface RedisRemindersOptions {
client?: RedisClient; // shared with the other providers
url?: string; // …or a URL — the package constructs an auto-pipelined client
namespace?: string; // 'sigx'
batchSize?: number; // 200 — members claimed per script
}
It throws unless client or url is given. Every operation — set, clear, a claim batch,
the re-arm of failed dispatches — is one Lua script, with Redis TIME as the clock. The claim
advances or removes a member before dispatch (at-most-once per firing); a periodic member
advances to max(next_due, now) + period, so downtime costs one firing rather than replaying
the gap. A tick keeps claiming batches until one comes back short, up to ten per tick, so
batchSize caps memory rather than throughput. The minimum period is 60 seconds, as with the
default provider.
remEscape / remUnescape are exported for tooling that reads the member encoding.
Types
RedisClient (the ioredis Redis type), RedisClusterOptions, RedisStorageOptions,
RedisRemindersOptions.
Key layout
{ns}:host:{hostId} HASH {d: descriptor JSON} PX ttlMs, renewed each beat
{ns}:hosts SET of hostIds lazily pruned
{ns}:mver INCR'd version counter cheap view-poll compare
{ns}:dir:{actorId} "hostId\nactivationId" no TTL (validity = owner liveness)
{ns}:membership pub/sub channel change push (poll = fallback)
{ns}:st:{type}\x00{key} HASH {e: etag, s: state JSON}
{ns}:rem:due ZSET score = next_due (ms), member = type\x00key\x00name
{ns}:rem:p HASH member → period ms (periodic reminders only)
{ns}:rem:a:{type}\x00{key} SET of the actor's reminder names — list() never scans
{ns}:sl:{type}\x00{key} LIST of appended entry JSON, oldest first
Reminder members escape each field (\ → \\, NUL → \0) so a NUL-bearing key splits back
into its ref and name.
The log has a prefix of its own (sl) rather than a suffix on the record key, because actor
keys are opaque and a suffix could collide with another actor's key.
The storage record key joins actor type and key with a NUL byte — the same actorId shape
the directory uses. Redis keys are binary-safe, and a NUL renders invisibly in
redis-cli SCAN output.
Directory entries carry no TTL: their validity is the owner's liveness, and entries for dead hosts are evicted lazily on lookup.
Operations used: the directory claim is SET NX GET; release and evict are Lua
compare-and-delete; evictHost is a SCAN plus an owner-prefix delete.
Next steps
- Overview — what it is for.
- Installation — options and tuning.
- Storage — the seam this implements.
