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

Information
Class: AsyncResponse.Transports.MongoDB.MongoDbReplyTargetOptions
Assembly: AsyncResponse.Transports.MongoDB
File(s): /home/runner/work/AsyncResponse/AsyncResponse/src/Transports/AsyncResponse.Transports.MongoDB/MongoDbAsyncResponseTransportOptions.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 243
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
.ctor()100%11100%

File(s)

/home/runner/work/AsyncResponse/AsyncResponse/src/Transports/AsyncResponse.Transports.MongoDB/MongoDbAsyncResponseTransportOptions.cs

#LineLine coverage
 1namespace AsyncResponse.Transports.MongoDB;
 2
 3/// <summary>Options for the MongoDB AsyncResponse transport.</summary>
 4public sealed class MongoDbAsyncResponseTransportOptions
 5{
 6    /// <summary>The transport name reported to reply targets and the startup validator.</summary>
 7    public const string TransportName = "MongoDB";
 8
 9    /// <summary>
 10    /// Optional MongoDB connection string used when no <c>IMongoDatabase</c> or <c>IMongoClient</c>
 11    /// is registered with the host.
 12    /// </summary>
 13    public string? ConnectionString { get; set; }
 14
 15    /// <summary>Optional database name used when no <c>IMongoDatabase</c> is registered.</summary>
 16    public string? DatabaseName { get; set; }
 17
 18    /// <summary>Collection storing worker, response-ingress, and dead-letter queue documents.</summary>
 19    public string MessageCollection { get; set; } = "asyncresponse_transport_messages";
 20
 21    /// <summary>Creates the claim and housekeeping indexes on first use. Disable when provisioning owns index DDL.</sum
 22    public bool AutoCreateIndexes { get; set; } = true;
 23
 24    /// <summary>
 25    /// Wakes idle subscribers with a change stream watching inserts to the queue collection.
 26    /// Requires a replica set; when disabled — or when the server reports change streams as
 27    /// unsupported — subscribers fall back to <see cref="MongoDbSubscriberOptions.EmptyPollDelay"/>
 28    /// polling. Default: <c>true</c>.
 29    /// </summary>
 30    public bool UseChangeStreamWake { get; set; } = true;
 31
 32    /// <summary>Logical queue name used by <see cref="MongoDbWorkerTransport"/>.</summary>
 33    public string WorkerQueue { get; set; } = "worker";
 34
 35    /// <summary>Worker queue handling options.</summary>
 36    public MongoDbSubscriberOptions WorkerSubscriber { get; } = new();
 37
 38    /// <summary>Logical queue name consumed by the hosted response-ingress subscriber.</summary>
 39    public string ResponseQueue { get; set; } = "response";
 40
 41    /// <summary>Response queue handling options.</summary>
 42    public MongoDbSubscriberOptions ResponseSubscriber { get; } = new();
 43
 44    /// <summary>Logical queue name that receives poison messages and already-ACKed background failures.</summary>
 45    public string DeadLetterQueue { get; set; } = "deadletter";
 46
 47    /// <summary>Enables dead-lettering when a message exhausts attempts or fails after early ACK.</summary>
 48    public bool DeadLetterEnabled { get; set; } = true;
 49
 50    /// <summary>
 51    /// How long dead-letter documents are retained before being pruned opportunistically. The
 52    /// dead-letter queue has no consumer by default, so without a retention its documents accumulate
 53    /// indefinitely. Leave <c>null</c> (the default) to keep them forever for manual inspection.
 54    /// </summary>
 55    public TimeSpan? DeadLetterRetention { get; set; }
 56
 57    /// <summary>How long a claimed document remains locked before another subscriber may retry it.</summary>
 58    public TimeSpan LockTimeout { get; set; } = TimeSpan.FromSeconds(30);
 59
 60    /// <summary>The logical reply target name used by <c>WithReplyTarget()</c>. Default: <c>default</c>.</summary>
 61    public string DefaultReplyTargetName { get; set; } = "default";
 62
 63    /// <summary>
 64    /// Named reply targets exposed to Core through <see cref="IAsyncResponseReplyTargetProvider"/>.
 65    /// When empty, <see cref="ResponseQueue"/> becomes the default target.
 66    /// </summary>
 67    public Dictionary<string, MongoDbReplyTargetOptions> ReplyTargets { get; } = new(StringComparer.Ordinal);
 68
 69    /// <summary>
 70    /// Header key stored in the document metadata for the AsyncResponse correlation id. Response
 71    /// messages may omit it when the id is present in the JSON body via <see cref="CorrelationIdJsonPaths"/>.
 72    /// </summary>
 73    public string CorrelationIdHeader { get; set; } = "AR-Correlation-Id";
 74
 75    /// <summary>
 76    /// JSON paths inspected when a response message does not carry the correlation id in
 77    /// <see cref="CorrelationIdHeader"/>. Paths are case-insensitive and support nested JSON strings.
 78    /// </summary>
 79    public string[] CorrelationIdJsonPaths { get; set; } =
 80    [
 81        "CorrelationId",
 82        "CustomParameters",
 83        "CustomParameters.CorrelationId",
 84        "PubSubParams.CustomParameters",
 85        "PubSubParams.CustomParameters.CorrelationId",
 86        "DagJsonParameters.CorrelationId"
 87    ];
 88
 89    /// <summary>Maximum attempts for MongoDB publish commands. Set to 1 to disable publish retries.</summary>
 90    public int PublishMaxAttempts { get; set; } = 3;
 91
 92    /// <summary>Initial delay before retrying a failed publish command.</summary>
 93    public TimeSpan PublishRetryBaseDelay { get; set; } = TimeSpan.FromMilliseconds(50);
 94
 95    /// <summary>Maximum delay between publish retry attempts.</summary>
 96    public TimeSpan PublishRetryMaxDelay { get; set; } = TimeSpan.FromSeconds(1);
 97
 98    /// <summary>Initial delay after a subscriber loop failure.</summary>
 99    public TimeSpan SubscriberRetryBaseDelay { get; set; } = TimeSpan.FromMilliseconds(100);
 100
 101    /// <summary>Maximum delay after repeated subscriber loop failures.</summary>
 102    public TimeSpan SubscriberRetryMaxDelay { get; set; } = TimeSpan.FromSeconds(5);
 103
 104    /// <summary>
 105    /// Bounds the wait for the change-stream listen task to join while a hosted subscriber stops.
 106    /// The join completes in milliseconds when healthy; when it does not, the task is abandoned
 107    /// anyway, so keep this short — it counts against the host's shutdown budget. Default: <c>5s</c>.
 108    /// </summary>
 109    public TimeSpan ShutdownTimeout { get; set; } = TimeSpan.FromSeconds(5);
 110
 111    /// <summary>
 112    /// The hosting shutdown budget that must contain MongoDB subscriber shutdown plus
 113    /// <see cref="MongoDbSubscriberOptions.BackgroundDrainTimeout"/> when a subscriber uses
 114    /// <see cref="MongoDbAckMode.AckAfterEnqueue"/>. Defaults to the Generic Host default of
 115    /// 30 seconds. Set to <c>null</c> only when this budget is validated externally.
 116    /// </summary>
 117    public TimeSpan? HostShutdownTimeout { get; set; } = TimeSpan.FromSeconds(30);
 118
 119    /// <summary>Adds or replaces a named MongoDB reply target.</summary>
 120    public MongoDbAsyncResponseTransportOptions AddReplyTarget(string name, string responseQueue)
 121    {
 122        ArgumentException.ThrowIfNullOrWhiteSpace(name);
 123        ArgumentException.ThrowIfNullOrWhiteSpace(responseQueue);
 124
 125        ReplyTargets[name] = new MongoDbReplyTargetOptions { ResponseQueue = responseQueue };
 126        return this;
 127    }
 128}
 129
 130/// <summary>Options for one named MongoDB async-response reply target.</summary>
 131public sealed class MongoDbReplyTargetOptions
 132{
 133    /// <summary>Queue remote systems should insert response payload documents into.</summary>
 134    public string? ResponseQueue { get; set; }
 135
 136    /// <summary>Additional values copied to the transport-neutral reply target.</summary>
 3137    public Dictionary<string, string> Properties { get; } = new(StringComparer.Ordinal);
 138}
 139
 140/// <summary>Controls when a MongoDB transport document is acknowledged relative to handling.</summary>
 141public enum MongoDbAckMode
 142{
 143    /// <summary>
 144    /// Delete the document only after the AsyncResponse handler completes successfully. Handler
 145    /// failures reschedule the document until <see cref="MongoDbSubscriberOptions.MaxDeliveryAttempts"/>
 146    /// is reached.
 147    /// </summary>
 148    AckAfterHandlerCompletes = 0,
 149
 150    /// <summary>
 151    /// Delete the document immediately after it is accepted into a bounded in-process background
 152    /// queue. Handler failures are logged, reported, and dead-lettered when enabled because the
 153    /// document has already been acknowledged.
 154    /// </summary>
 155    AckAfterEnqueue = 1
 156}
 157
 158/// <summary>Describes a handler failure that happened after a MongoDB document was already acknowledged.</summary>
 159public sealed class MongoDbBackgroundFailureContext
 160{
 161    internal MongoDbBackgroundFailureContext(string queue, string subscriberRole, int attempt, string? correlationId, Ex
 162    {
 163        Queue = queue;
 164        SubscriberRole = subscriberRole;
 165        Attempt = attempt;
 166        CorrelationId = correlationId;
 167        Exception = exception;
 168    }
 169
 170    /// <summary>The logical queue the document came from.</summary>
 171    public string Queue { get; }
 172
 173    /// <summary>The logical subscriber role, such as <c>Worker</c> or <c>ResponseIngress</c>.</summary>
 174    public string SubscriberRole { get; }
 175
 176    /// <summary>The delivery attempt count for the document.</summary>
 177    public int Attempt { get; }
 178
 179    /// <summary>The AsyncResponse correlation id, when one was available.</summary>
 180    public string? CorrelationId { get; }
 181
 182    /// <summary>The exception thrown by the background handler.</summary>
 183    public Exception Exception { get; }
 184}
 185
 186/// <summary>Per-queue MongoDB subscriber behavior.</summary>
 187public sealed class MongoDbSubscriberOptions
 188{
 189    /// <summary>Controls when a document is acknowledged. Defaults to <see cref="MongoDbAckMode.AckAfterHandlerComplete
 190    public MongoDbAckMode AckMode { get; set; } = MongoDbAckMode.AckAfterHandlerCompletes;
 191
 192    /// <summary>
 193    /// Maximum documents claimed per subscriber loop pass. In the default
 194    /// <see cref="MongoDbAckMode.AckAfterHandlerCompletes"/> mode the claimed documents are handled
 195    /// one at a time, so this bounds claim round-trips, not handler concurrency. Use
 196    /// <see cref="MongoDbAckMode.AckAfterEnqueue"/> (or run multiple subscriber instances) to
 197    /// process messages in parallel. Default: <c>16</c>.
 198    /// </summary>
 199    public int BatchSize { get; set; } = 16;
 200
 201    /// <summary>
 202    /// Maximum delivery attempts before a failing document is deleted and written to the dead-letter
 203    /// queue. <c>0</c> means unlimited retries. Default: <c>5</c>.
 204    /// </summary>
 205    public int MaxDeliveryAttempts { get; set; } = 5;
 206
 207    /// <summary>Delay before a failed document becomes available for redelivery. Default: <c>5s</c>.</summary>
 208    public TimeSpan RedeliveryDelay { get; set; } = TimeSpan.FromSeconds(5);
 209
 210    /// <summary>Delay after an empty poll before checking again. Default: <c>250ms</c>.</summary>
 211    public TimeSpan EmptyPollDelay { get; set; } = TimeSpan.FromMilliseconds(250);
 212
 213    /// <summary>Number of background workers used by <see cref="MongoDbAckMode.AckAfterEnqueue"/>.</summary>
 214    public int BackgroundWorkerCount { get; set; }
 215
 216    /// <summary>Maximum number of ACKed documents waiting in the background queue.</summary>
 217    public int BackgroundQueueCapacity { get; set; }
 218
 219    /// <summary>Maximum time to wait for queued/running background handlers while stopping.</summary>
 220    public TimeSpan BackgroundDrainTimeout { get; set; } = TimeSpan.FromSeconds(20);
 221
 222    /// <summary>Optional callback invoked when a background handler fails after the document was already acknowledged.<
 223    public Func<MongoDbBackgroundFailureContext, ValueTask>? OnBackgroundFailure { get; set; }
 224
 225    /// <summary>Explicitly opts this subscriber into ACK-after-enqueue behavior.</summary>
 226    public MongoDbSubscriberOptions UseAckAfterEnqueue(
 227        int backgroundWorkerCount,
 228        int backgroundQueueCapacity,
 229        TimeSpan? backgroundDrainTimeout = null)
 230    {
 231        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(backgroundWorkerCount);
 232        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(backgroundQueueCapacity);
 233        if (backgroundDrainTimeout is { } timeout && timeout <= TimeSpan.Zero)
 234            throw new ArgumentOutOfRangeException(nameof(backgroundDrainTimeout), timeout, "Drain timeout must be positi
 235
 236        AckMode = MongoDbAckMode.AckAfterEnqueue;
 237        BackgroundWorkerCount = backgroundWorkerCount;
 238        BackgroundQueueCapacity = backgroundQueueCapacity;
 239        if (backgroundDrainTimeout is not null)
 240            BackgroundDrainTimeout = backgroundDrainTimeout.Value;
 241        return this;
 242    }
 243}

Methods/Properties

.ctor()