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

Information
Class: AsyncResponse.FlowLeaseContention
Assembly: AsyncResponse.Core
File(s): /_/src/AsyncResponse.Core/FlowLeaseContention.cs
Line coverage
100%
Covered lines: 27
Uncovered lines: 0
Coverable lines: 27
Total lines: 119
Line coverage: 100%
Branch coverage
100%
Covered branches: 26
Total branches: 26
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
JobTag(...)100%88100%
NewLeaseId(...)100%22100%
JobTagOf(...)100%66100%
Judge(...)100%1010100%

File(s)

/_/src/AsyncResponse.Core/FlowLeaseContention.cs

#LineLine coverage
 1using System.Security.Cryptography;
 2using System.Text;
 3
 4namespace AsyncResponse;
 5
 6/// <summary>What a contended wake-up may conclude from two observations of the lease in its way.</summary>
 7internal enum FlowLeaseContentionVerdict
 8{
 9    /// <summary>
 10    /// The lease has not changed since the baseline: no proof of a live holder. A dead holder's
 11    /// lease reads exactly like this, so the wake-up keeps waiting (to the persisted expiry).
 12    /// </summary>
 13    KeepWaiting,
 14
 15    /// <summary>
 16    /// A live worker acquired or renewed the lease while this wake-up waited, and that execution
 17    /// is driven by a DIFFERENT job (or one of the two carries no job identity). The holder's own
 18    /// job is still unacknowledged at the broker, so this delivery is redundant and safe to ack.
 19    /// </summary>
 20    AcknowledgeDuplicate,
 21
 22    /// <summary>
 23    /// A live worker holds the lease — and the job driving it is THIS delivery's job. The broker
 24    /// redelivered a job whose handler is still running (an in-flight ceiling lapsed), so this
 25    /// delivery is the only copy of the run's wake-up the broker still has: never a duplicate.
 26    /// </summary>
 27    HolderOwnJobRedelivered
 28}
 29
 30/// <summary>
 31/// The job identity recorded with a durable-flow execution lease, and the decision a contended
 32/// wake-up takes from it. Pure, so the rule is testable without a store, a clock, or a transport.
 33/// <para>
 34/// The identity rides INSIDE the lease id — <c>{guid:N}.{tag}</c> — because that is the one value
 35/// every store already writes atomically with the acquire and reports back through
 36/// <see cref="IFlowStateStore.ObserveLeaseAsync"/>: no store, schema, or wire change. The tag is a
 37/// fixed-width digest of <see cref="WorkerJobEnvelope.JobId"/> rather than the id itself, since a
 38/// job id is a wire value a foreign producer controls and the relational stores keep the lease id
 39/// in a 64-character column (32 + 1 + <see cref="JobTagLength"/> = 55).
 40/// </para>
 41/// </summary>
 42internal static class FlowLeaseContention
 43{
 44    /// <summary>Characters of base64url(SHA-256) kept as the tag: 132 bits.</summary>
 45    internal const int JobTagLength = 22;
 46
 47    private const int GuidLength = 32;
 48    private const char Separator = '.';
 49
 50    /// <summary>The lease tag for <paramref name="jobId"/>, or <c>null</c> for a job without an identity.</summary>
 51    public static string? JobTag(string? jobId)
 52    {
 207153        if (string.IsNullOrEmpty(jobId))
 18254            return null;
 55
 188956        Span<byte> digest = stackalloc byte[SHA256.HashSizeInBytes];
 188957        SHA256.HashData(Encoding.UTF8.GetBytes(jobId), digest);
 58
 59        // 32 bytes encode to 44 base64 characters (padding included); the tag is the first 22,
 60        // rewritten to the URL-safe alphabet so it is inert in every store's id column.
 188961        Span<char> encoded = stackalloc char[44];
 188962        Convert.TryToBase64Chars(digest, encoded, out _);
 8689463        for (var i = 0; i < JobTagLength; i++)
 64        {
 4155865            encoded[i] = encoded[i] switch
 4155866            {
 64867                '+' => '-',
 68368                '/' => '_',
 4022769                var other => other
 4155870            };
 71        }
 72
 188973        return new string(encoded[..JobTagLength]);
 74    }
 75
 76    /// <summary>
 77    /// A fresh lease id recording <paramref name="jobTag"/>; the plain 32-character id when the
 78    /// execution is not driven by an identified job (a direct call, or a job written before
 79    /// <see cref="WorkerJobEnvelope.JobId"/> existed).
 80    /// </summary>
 81    public static string NewLeaseId(string? jobTag)
 82    {
 633583        var unique = Guid.NewGuid().ToString("N");
 633584        return jobTag is null ? unique : string.Concat(unique, ".", jobTag);
 85    }
 86
 87    /// <summary>
 88    /// The job tag recorded in <paramref name="leaseId"/>, or <c>null</c> when it carries none: a
 89    /// lease issued by an older build, by a direct execution, or by anything else that does not
 90    /// write this exact shape.
 91    /// </summary>
 92    public static string? JobTagOf(string? leaseId)
 24093        => leaseId is { Length: GuidLength + 1 + JobTagLength } && leaseId[GuidLength] == Separator
 24094            ? leaseId[(GuidLength + 1)..]
 24095            : null;
 96
 97    /// <summary>
 98    /// Judges the lease in the way of a wake-up driven by the job tagged <paramref name="ownJobTag"/>
 99    /// (<c>null</c> when the delivery has no identity), given the first observation of that lease
 100    /// and the current one.
 101    /// </summary>
 102    public static FlowLeaseContentionVerdict Judge(
 103        FlowLeaseObservation baseline,
 104        FlowLeaseObservation observed,
 105        string? ownJobTag)
 106    {
 107        // Only a worker that acquired or renewed the lease AFTER the baseline can have written a
 108        // different owner or a later expiry; an unchanged pair proves nothing.
 4117109        var changed = !string.Equals(observed.LeaseId, baseline.LeaseId, StringComparison.Ordinal)
 4117110            || observed.ExpiresAtUtc > baseline.ExpiresAtUtc;
 4117111        if (!changed)
 3889112            return FlowLeaseContentionVerdict.KeepWaiting;
 113
 228114        return ownJobTag is not null
 228115            && string.Equals(JobTagOf(observed.LeaseId), ownJobTag, StringComparison.Ordinal)
 228116                ? FlowLeaseContentionVerdict.HolderOwnJobRedelivered
 228117                : FlowLeaseContentionVerdict.AcknowledgeDuplicate;
 118    }
 119}