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

Information
Class: AsyncResponse.Transports.NATS.NatsReplyTargetOptions
Assembly: AsyncResponse.Transports.NATS
File(s): /_/src/Transports/AsyncResponse.Transports.NATS/NatsAsyncResponseTransportOptions.cs
Line coverage
100%
Covered lines: 3
Uncovered lines: 0
Coverable lines: 3
Total lines: 170
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_ResponseSubject()100%11100%
get_Consumer()100%11100%
get_Properties()100%11100%

File(s)

/_/src/Transports/AsyncResponse.Transports.NATS/NatsAsyncResponseTransportOptions.cs

#LineLine coverage
 1namespace AsyncResponse.Transports.NATS;
 2
 3/// <summary>
 4/// Options for the NATS JetStream AsyncResponse transport. Requires a NATS server with JetStream
 5/// enabled.
 6/// </summary>
 7public sealed class NatsAsyncResponseTransportOptions
 8{
 9    /// <summary>The transport name reported to reply targets and the startup validator.</summary>
 10    public const string TransportName = "NATS";
 11
 12    /// <summary>
 13    /// Prefix used to derive subject and stream names that are not explicitly configured. The default
 14    /// worker subject is <c>{SubjectPrefix}.transport.worker</c>, the response subject is
 15    /// <c>{SubjectPrefix}.transport.response</c>, and the dead-letter subject is
 16    /// <c>{SubjectPrefix}.transport.deadletter</c>. Stream names replace the dots with underscores
 17    /// (NATS stream names cannot contain dots). Use a unique prefix per app/environment when several
 18    /// deployments share one NATS system.
 19    /// </summary>
 20    public string SubjectPrefix { get; set; } = "asyncresponse";
 21
 22    /// <summary>NATS subject worker jobs are published to. When null, <see cref="SubjectPrefix"/> determines it.</summa
 23    public string? WorkerSubject { get; set; }
 24
 25    /// <summary>JetStream stream that captures the worker subject. When null, <see cref="SubjectPrefix"/> determines it
 26    public string? WorkerStream { get; set; }
 27
 28    /// <summary>Durable JetStream consumer used by the hosted worker subscriber.</summary>
 29    public string WorkerConsumer { get; set; } = "asyncresponse-workers";
 30
 31    /// <summary>Worker subject handling options.</summary>
 32    public NatsSubscriberOptions WorkerSubscriber { get; } = new();
 33
 34    /// <summary>
 35    /// NATS subject remote systems publish response payloads to. The hosted response-ingress
 36    /// subscriber consumes it and forwards payloads into <see cref="IAsyncResponseIngress"/>. When
 37    /// null, <see cref="SubjectPrefix"/> determines it.
 38    /// </summary>
 39    public string? ResponseSubject { get; set; }
 40
 41    /// <summary>JetStream stream that captures the response subject. When null, <see cref="SubjectPrefix"/> determines 
 42    public string? ResponseStream { get; set; }
 43
 44    /// <summary>Durable JetStream consumer used by the hosted response-ingress subscriber.</summary>
 45    public string ResponseConsumer { get; set; } = "asyncresponse-responses";
 46
 47    /// <summary>Response subject handling options.</summary>
 48    public NatsSubscriberOptions ResponseSubscriber { get; } = new();
 49
 50    /// <summary>
 51    /// Creates the worker and response JetStream streams (and the dead-letter stream when enabled) on
 52    /// subscriber startup when they do not exist. A stream that already exists is never modified:
 53    /// startup fails when it does not capture the configured subject or (worker/response streams)
 54    /// does not use work-queue retention, and logs a warning when its discard policy or message
 55    /// limit differs from these options — settings tuned on the live stream (replicas, max age,
 56    /// max bytes, …) are left alone. Disable when streams are provisioned out of band.
 57    /// </summary>
 58    public bool CreateStreams { get; set; } = true;
 59
 60    /// <summary>
 61    /// Maximum message count retained per worker/response stream. Set null to disable the limit.
 62    /// Applied when this library creates the stream; a later change is reported as drift, not
 63    /// applied to the existing stream.
 64    /// </summary>
 65    public long? StreamMaxMessages { get; set; } = 100_000;
 66
 67    /// <summary>
 68    /// Replica count (JetStream <c>num_replicas</c>) for the streams this library creates: worker,
 69    /// response, and dead-letter. <c>1</c>–<c>5</c>; use an odd number (3 or 5) on a clustered
 70    /// JetStream — an even count tolerates no more failures than the odd count below it. Values
 71    /// above 1 require a JetStream cluster with at least that many servers. Only applied when a
 72    /// stream is created; an existing stream keeps its replica count. Default: <c>1</c>.
 73    /// </summary>
 74    public int StreamReplicas { get; set; } = 1;
 75
 76    /// <summary>How long the server waits for an ACK before redelivering a message (the JetStream AckWait).</summary>
 77    public TimeSpan AckWait { get; set; } = TimeSpan.FromSeconds(30);
 78
 79    /// <summary>
 80    /// Enables dead-lettering when a message reaches
 81    /// <see cref="NatsSubscriberOptions.MaxDeliveryAttempts"/> or a background handler fails after an
 82    /// early ACK. When true and <see cref="DeadLetterSubject"/> is null, <see cref="SubjectPrefix"/>
 83    /// determines the subject/stream names.
 84    /// </summary>
 85    public bool DeadLetterEnabled { get; set; } = true;
 86
 87    /// <summary>NATS subject that receives poison messages and already-ACKed background failures.</summary>
 88    public string? DeadLetterSubject { get; set; }
 89
 90    /// <summary>JetStream stream that captures the dead-letter subject.</summary>
 91    public string? DeadLetterStream { get; set; }
 92
 93    /// <summary>Maximum dead-letter stream message count. Set null to disable the limit.</summary>
 94    public long? DeadLetterStreamMaxMessages { get; set; } = 100_000;
 95
 96    /// <summary>The logical reply target name used by <c>WithReplyTarget()</c>. Default: <c>default</c>.</summary>
 97    public string DefaultReplyTargetName { get; set; } = "default";
 98
 99    /// <summary>
 100    /// Named reply targets exposed to Core through <see cref="IAsyncResponseReplyTargetProvider"/>.
 101    /// When empty, the resolved <see cref="ResponseSubject"/> becomes the default target.
 102    /// </summary>
 103    public Dictionary<string, NatsReplyTargetOptions> ReplyTargets { get; } = new(StringComparer.Ordinal);
 104
 105    /// <summary>
 106    /// NATS message header carrying the AsyncResponse correlation id. Response messages may omit it
 107    /// when the id is present in the JSON body via <see cref="CorrelationIdJsonPaths"/>.
 108    /// </summary>
 109    public string CorrelationIdHeader { get; set; } = "AR-Correlation-Id";
 110
 111    /// <summary>
 112    /// JSON paths inspected when a response message does not carry the correlation id in
 113    /// <see cref="CorrelationIdHeader"/>. Paths are case-insensitive and support nested JSON strings.
 114    /// </summary>
 115    public string[] CorrelationIdJsonPaths { get; set; } =
 116    [
 117        "CorrelationId",
 118        "CustomParameters",
 119        "CustomParameters.CorrelationId",
 120        "PubSubParams.CustomParameters",
 121        "PubSubParams.CustomParameters.CorrelationId",
 122        "DagJsonParameters.CorrelationId"
 123    ];
 124
 125    /// <summary>Maximum attempts for JetStream publish commands. Set to 1 to disable publish retries.</summary>
 126    public int PublishMaxAttempts { get; set; } = 3;
 127
 128    /// <summary>Initial delay before retrying a failed publish command.</summary>
 129    public TimeSpan PublishRetryBaseDelay { get; set; } = TimeSpan.FromMilliseconds(50);
 130
 131    /// <summary>Maximum delay between publish retry attempts.</summary>
 132    public TimeSpan PublishRetryMaxDelay { get; set; } = TimeSpan.FromSeconds(1);
 133
 134    /// <summary>Initial delay after a subscriber consume-loop failure.</summary>
 135    public TimeSpan SubscriberRetryBaseDelay { get; set; } = TimeSpan.FromMilliseconds(100);
 136
 137    /// <summary>Maximum delay after repeated subscriber consume-loop failures.</summary>
 138    public TimeSpan SubscriberRetryMaxDelay { get; set; } = TimeSpan.FromSeconds(5);
 139
 140    /// <summary>
 141    /// The hosting shutdown budget that must contain
 142    /// <see cref="NatsSubscriberOptions.BackgroundDrainTimeout"/> when a subscriber uses
 143    /// <see cref="NatsAckMode.AckAfterEnqueue"/>. Defaults to the Generic Host default of
 144    /// 30 seconds. Set to <c>null</c> only when this budget is validated externally.
 145    /// </summary>
 146    public TimeSpan? HostShutdownTimeout { get; set; } = TimeSpan.FromSeconds(30);
 147
 148    /// <summary>Adds or replaces a named NATS reply target.</summary>
 149    public NatsAsyncResponseTransportOptions AddReplyTarget(string name, string responseSubject)
 150    {
 151        ArgumentException.ThrowIfNullOrWhiteSpace(name);
 152        ArgumentException.ThrowIfNullOrWhiteSpace(responseSubject);
 153
 154        ReplyTargets[name] = new NatsReplyTargetOptions { ResponseSubject = responseSubject };
 155        return this;
 156    }
 157}
 158
 159/// <summary>Options for one named NATS JetStream async-response reply target.</summary>
 160public sealed class NatsReplyTargetOptions
 161{
 162    /// <summary>NATS subject remote systems should publish response payloads to.</summary>
 20163    public string? ResponseSubject { get; set; }
 164
 165    /// <summary>Durable consumer that receives responses for this target. Optional metadata.</summary>
 12166    public string? Consumer { get; set; }
 167
 168    /// <summary>Additional values copied to the transport-neutral reply target.</summary>
 16169    public Dictionary<string, string> Properties { get; } = new(StringComparer.Ordinal);
 170}