< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: AsyncResponse.Transports.Redis.RedisTransportKeySchema
Assembly: AsyncResponse.Transports.Redis
File(s): /_/src/Transports/AsyncResponse.Transports.Redis/RedisTransportKeySchema.cs
Line coverage
100%
Covered lines: 13
Uncovered lines: 0
Coverable lines: 13
Total lines: 45
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_WorkerStream()100%11100%
get_ResponseStream()100%11100%
get_DeadLetterStream()100%11100%
WorkerPublishDedupKey(...)100%11100%
HashTagOf(...)100%44100%
Resolve(...)100%22100%

File(s)

/_/src/Transports/AsyncResponse.Transports.Redis/RedisTransportKeySchema.cs

#LineLine coverage
 1using StackExchange.Redis;
 2
 3namespace AsyncResponse.Transports.Redis;
 4
 5/// <summary>
 6/// Resolves Redis stream names from transport options. These names are deployment contracts: changing
 7/// them while entries are in flight strands unprocessed worker or response messages in the old stream.
 8/// </summary>
 33339internal sealed class RedisTransportKeySchema(RedisAsyncResponseTransportOptions _options)
 10{
 1037011    public RedisKey WorkerStream => Resolve(_options.WorkerStream, "worker");
 625712    public RedisKey ResponseStream => Resolve(_options.ResponseStream, "response");
 184113    public RedisKey DeadLetterStream => Resolve(_options.DeadLetterStream, "deadletter");
 14
 15    /// <summary>
 16    /// Per-publish dedup marker for the idempotent worker XADD. Hash-tagged with the stream's own
 17    /// slot key so the marker and the stream share a cluster slot — the MULTI/EXEC that couples
 18    /// them would otherwise fail with CROSSSLOT on Redis Cluster. Wrapping the whole stream name
 19    /// in braces nested them when the name already carried a hash tag (the idiomatic
 20    /// <c>KeyPrefix = "{app}"</c> co-location), and Redis then read <c>{app</c> as the marker's
 21    /// tag — a different slot, and CROSSSLOT on every publish.
 22    /// </summary>
 23    public RedisKey WorkerPublishDedupKey(string publishId)
 42324        => $"{{{HashTagOf(((string?)WorkerStream)!)}}}:publish:{publishId}";
 25
 26    /// <summary>
 27    /// The key text Redis Cluster hashes for <paramref name="key"/>: the substring between the
 28    /// first <c>{</c> and the first <c>}</c> after it when that is non-empty, otherwise the whole
 29    /// key. A name whose braces do not form one such tag returns unchanged — see the validator,
 30    /// which rejects those, because no marker key could then share the stream's slot.
 31    /// </summary>
 32    internal static string HashTagOf(string key)
 33    {
 43134        var open = key.IndexOf('{');
 43135        if (open < 0)
 42136            return key;
 1037        var close = key.IndexOf('}', open + 1);
 1038        return close > open + 1 ? key.Substring(open + 1, close - open - 1) : key;
 39    }
 40
 41    private RedisKey Resolve(string? configured, string role)
 1846842        => !string.IsNullOrWhiteSpace(configured)
 1846843            ? configured
 1846844            : $"{_options.KeyPrefix}:transport:{role}";
 45}