RedisDeliveryLease Class
The delivery lease across instances, on the one Redis primitive that can express it: a write conditional on the key not existing, carrying its own expiry. Every transmitter instance asks the same server, so exactly one of them is told yes.
public sealed class RedisDeliveryLease : Abblix.SharedSignals.Transmitter.IDeliveryLeaseInheritance System.Object → RedisDeliveryLease
Implements IDeliveryLease
Remarks
This is why the lease is not offered over IDistributedCache. That interface writes whole
values unconditionally - it has no set-if-absent - so a lease built on it would be taken by
every instance that asked, and a lock everyone holds is worse than none: the sweep would look
coordinated while behaving exactly as it does with no lease at all.
Releasing compares before deleting, and the case it exists for is the ordinary one rather than an exotic race: a holder whose pass ran past the deadline no longer owns the name, another instance has taken it, and an unconditional delete would hand the name to a third while the second was still working. The comparison and the delete are one script because reading and then deleting is that same defect with a smaller window.
One key per name, so the script is single-key and needs no cluster hash tag to stay valid under Redis Cluster.
Constructors
RedisDeliveryLease(IConnectionMultiplexer) Constructor
The delivery lease across instances, on the one Redis primitive that can express it: a write conditional on the key not existing, carrying its own expiry. Every transmitter instance asks the same server, so exactly one of them is told yes.
public RedisDeliveryLease(StackExchange.Redis.IConnectionMultiplexer connection);Parameters
connection StackExchange.Redis.IConnectionMultiplexer
The Redis connection; opening and configuring it is the host's.
Remarks
This is why the lease is not offered over IDistributedCache. That interface writes whole
values unconditionally - it has no set-if-absent - so a lease built on it would be taken by
every instance that asked, and a lock everyone holds is worse than none: the sweep would look
coordinated while behaving exactly as it does with no lease at all.
Releasing compares before deleting, and the case it exists for is the ordinary one rather than an exotic race: a holder whose pass ran past the deadline no longer owns the name, another instance has taken it, and an unconditional delete would hand the name to a third while the second was still working. The comparison and the delete are one script because reading and then deleting is that same defect with a smaller window.
One key per name, so the script is single-key and needs no cluster hash tag to stay valid under Redis Cluster.
Methods
RedisDeliveryLease.TryAcquireAsync(string, TimeSpan, CancellationToken) Method
Claims name for at most duration.
public System.Threading.Tasks.Task<System.IAsyncDisposable?> TryAcquireAsync(string name, System.TimeSpan duration, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken));Parameters
name System.String
What is being claimed. Callers scope it themselves, so two kinds of work over one stream do not collide.
duration System.TimeSpan
How long the claim holds without being released. It bounds two opposite costs: too short cuts a legitimate pass off and the work is redone next time, too long parks the work for the remainder after the holder dies. Both are safe, so err on whichever the deployment minds less.
cancellationToken System.Threading.CancellationToken
Cancels the I/O a shared implementation performs.
Implements TryAcquireAsync(string, TimeSpan, CancellationToken)
Returns
System.Threading.Tasks.Task<System.IAsyncDisposable>
A handle that releases the claim when disposed, or null when someone else holds it - which
is an ordinary outcome and not a failure. Releasing is conditional on still holding it, so
a handle disposed after its deadline cannot revoke the claim of whoever took over.