Skip to content

CSHARP-3549: CSOT: Add timeoutMS to settings #1721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/MongoDB.Driver/AggregateOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2015-present MongoDB Inc.
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -34,6 +34,7 @@ public class AggregateOptions
private BsonDocument _let;
private TimeSpan? _maxAwaitTime;
private TimeSpan? _maxTime;
private TimeSpan? _timeout;
private ExpressionTranslationOptions _translationOptions;
private bool? _useCursor;

Expand Down Expand Up @@ -127,6 +128,16 @@ public TimeSpan? MaxTime
set { _maxTime = Ensure.IsNullOrInfiniteOrGreaterThanOrEqualToZero(value, nameof(value)); }
}

/// <summary>
/// Gets or sets the operation timeout.
/// </summary>
// TODO: CSOT: Make it public when CSOT will be ready for GA
internal TimeSpan? Timeout
{
get => _timeout;
set => _timeout = Ensure.IsNullOrValidTimeout(value, nameof(Timeout));
}

/// <summary>
/// Gets or sets the translation options.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions src/MongoDB.Driver/BulkWriteOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
* limitations under the License.
*/

using System;
using MongoDB.Bson;
using MongoDB.Driver.Core.Misc;

namespace MongoDB.Driver
{
Expand All @@ -27,6 +29,7 @@ public sealed class BulkWriteOptions
private BsonValue _comment;
private bool _isOrdered;
private BsonDocument _let;
private TimeSpan? _timeout;

// constructors
/// <summary>
Expand Down Expand Up @@ -73,5 +76,15 @@ public BsonDocument Let
get { return _let; }
set { _let = value; }
}

/// <summary>
/// Gets or sets the operation timeout.
/// </summary>
// TODO: CSOT: Make it public when CSOT will be ready for GA
internal TimeSpan? Timeout
{
get => _timeout;
set => _timeout = Ensure.IsNullOrValidTimeout(value, nameof(Timeout));
}
}
}
13 changes: 12 additions & 1 deletion src/MongoDB.Driver/ChangeStreamOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2017-present MongoDB Inc.
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,6 +35,7 @@ public class ChangeStreamOptions
private bool? _showExpandedEvents;
private BsonDocument _startAfter;
private BsonTimestamp _startAtOperationTime;
private TimeSpan? _timeout;

// public properties
/// <summary>
Expand Down Expand Up @@ -166,5 +167,15 @@ public BsonTimestamp StartAtOperationTime
get { return _startAtOperationTime; }
set { _startAtOperationTime = value; }
}

/// <summary>
/// Gets or sets the operation timeout.
/// </summary>
// TODO: CSOT: Make it public when CSOT will be ready for GA
internal TimeSpan? Timeout
{
get => _timeout;
set => _timeout = Ensure.IsNullOrValidTimeout(value, nameof(Timeout));
}
}
}
14 changes: 14 additions & 0 deletions src/MongoDB.Driver/ClientBulkWriteOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
* limitations under the License.
*/

using System;
using MongoDB.Bson;
using MongoDB.Driver.Core.Misc;

namespace MongoDB.Driver
{
Expand All @@ -22,6 +24,8 @@ namespace MongoDB.Driver
/// </summary>
public sealed class ClientBulkWriteOptions
{
private TimeSpan? _timeout;

/// <summary>
/// Initializes a new instance of the <see cref="BulkWriteOptions"/> class.
/// </summary>
Expand Down Expand Up @@ -75,6 +79,16 @@ public ClientBulkWriteOptions(
/// </summary>
public BsonDocument Let { get; set; }

/// <summary>
/// Gets or sets the operation timeout.
/// </summary>
// TODO: CSOT: Make it public when CSOT will be ready for GA
internal TimeSpan? Timeout
{
get => _timeout;
set => _timeout = Ensure.IsNullOrValidTimeout(value, nameof(Timeout));
}

/// <summary>
/// Whether detailed results for each successful operation should be included in the returned results.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions src/MongoDB.Driver/Core/Bindings/CoreSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public bool IsInTransaction
EnsureAbortTransactionCanBeCalled(nameof(AbortTransaction));

// TODO: CSOT implement proper way to obtain the operationContext
var operationContext = new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken);
var operationContext = new OperationContext(null, cancellationToken);
try
{
if (_currentTransaction.IsEmpty)
Expand Down Expand Up @@ -197,7 +197,7 @@ public bool IsInTransaction
EnsureAbortTransactionCanBeCalled(nameof(AbortTransaction));

// TODO: CSOT implement proper way to obtain the operationContext
var operationContext = new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken);
var operationContext = new OperationContext(null, cancellationToken);
try
{
if (_currentTransaction.IsEmpty)
Expand Down Expand Up @@ -297,7 +297,7 @@ public long AdvanceTransactionNumber()
EnsureCommitTransactionCanBeCalled(nameof(CommitTransaction));

// TODO: CSOT implement proper way to obtain the operationContext
var operationContext = new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken);
var operationContext = new OperationContext(null, cancellationToken);
try
{
_isCommitTransactionInProgress = true;
Expand Down Expand Up @@ -334,7 +334,7 @@ public long AdvanceTransactionNumber()
EnsureCommitTransactionCanBeCalled(nameof(CommitTransaction));

// TODO: CSOT implement proper way to obtain the operationContext
var operationContext = new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken);
var operationContext = new OperationContext(null, cancellationToken);
try
{
_isCommitTransactionInProgress = true;
Expand Down
16 changes: 15 additions & 1 deletion src/MongoDB.Driver/Core/Configuration/ConnectionString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ public sealed class ConnectionString
private TimeSpan? _socketTimeout;
private int? _srvMaxHosts;
private string _srvServiceName;
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
private TimeSpan? _timeout;
#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value
private bool? _tls;
private bool? _tlsDisableCertificateRevocationCheck;
private bool? _tlsInsecure;
Expand Down Expand Up @@ -399,7 +402,6 @@ public bool? RetryReads
get { return _retryReads; }
}


/// <summary>
/// Gets a value indicating whether or not to retry writes.
/// </summary>
Expand Down Expand Up @@ -468,6 +470,12 @@ public bool? Ssl
[Obsolete("Use TlsInsecure instead.")]
public bool? SslVerifyCertificate => !_tlsInsecure;

/// <summary>
/// Gets the per-operation timeout.
/// </summary>
// TODO: CSOT: Make it public when CSOT will be ready for GA
internal TimeSpan? Timeout => _timeout;

/// <summary>
/// Gets whether to use TLS.
/// </summary>
Expand Down Expand Up @@ -1089,6 +1097,12 @@ private void ParseOption(string name, string value)
var sslVerifyCertificateValue = ParseBoolean(name, value);
_tlsInsecure = EnsureTlsInsecureIsValid(!sslVerifyCertificateValue);
break;
#if DEBUG // TODO: CSOT: Make it public when CSOT will be ready for GA
case "timeout":
case "timeoutms":
_timeout = value == "0" ? System.Threading.Timeout.InfiniteTimeSpan : ParseTimeSpan(name, value);
break;
#endif
case "tlsdisablecertificaterevocationcheck":
var tlsDisableCertificateRevocationCheckValue = ParseBoolean(name, value);
_tlsDisableCertificateRevocationCheck =
Expand Down
5 changes: 2 additions & 3 deletions src/MongoDB.Driver/Core/Misc/Ensure.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2013-present MongoDB Inc.
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -461,8 +461,7 @@ public static TimeSpan IsValidTimeout(TimeSpan value, string paramName)
{
if (value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
{
var message = string.Format("Invalid timeout: {0}.", value);
throw new ArgumentException(message, paramName);
throw new ArgumentOutOfRangeException($"Invalid timeout: {value}.", paramName);
}
return value;
}
Expand Down
4 changes: 2 additions & 2 deletions src/MongoDB.Driver/Core/Misc/Feature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ public void ThrowIfNotSupported(IMongoClient client, CancellationToken cancellat
{
var cluster = client.GetClusterInternal();
// TODO: CSOT implement proper way to obtain the operationContext
var operationContext = new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken);
var operationContext = new OperationContext(null, cancellationToken);
using (var binding = new ReadWriteBindingHandle(new WritableServerBinding(cluster, NoCoreSession.NewHandle())))
using (var channelSource = binding.GetWriteChannelSource(operationContext))
using (var channel = channelSource.GetChannel(operationContext))
Expand All @@ -589,7 +589,7 @@ public async Task ThrowIfNotSupportedAsync(IMongoClient client, CancellationToke
{
var cluster = client.GetClusterInternal();
// TODO: CSOT implement proper way to obtain the operationContext
var operationContext = new OperationContext(Timeout.InfiniteTimeSpan, cancellationToken);
var operationContext = new OperationContext(null, cancellationToken);
using (var binding = new ReadWriteBindingHandle(new WritableServerBinding(cluster, NoCoreSession.NewHandle())))
using (var channelSource = await binding.GetWriteChannelSourceAsync(operationContext).ConfigureAwait(false))
using (var channel = await channelSource.GetChannelAsync(operationContext).ConfigureAwait(false))
Expand Down
12 changes: 6 additions & 6 deletions src/MongoDB.Driver/Core/Operations/AggregateOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public IAsyncCursor<TResult> Execute(OperationContext operationContext, Retryabl

using (EventContext.BeginOperation())
{
var operation = CreateOperation(context);
var operation = CreateOperation(operationContext, context);
var result = operation.Execute(operationContext, context);

context.ChannelSource.Session.SetSnapshotTimeIfNeeded(result.AtClusterTime);
Expand Down Expand Up @@ -317,7 +317,7 @@ public async Task<IAsyncCursor<TResult>> ExecuteAsync(OperationContext operation

using (EventContext.BeginOperation())
{
var operation = CreateOperation(context);
var operation = CreateOperation(operationContext, context);
var result = await operation.ExecuteAsync(operationContext, context).ConfigureAwait(false);

context.ChannelSource.Session.SetSnapshotTimeIfNeeded(result.AtClusterTime);
Expand All @@ -326,15 +326,15 @@ public async Task<IAsyncCursor<TResult>> ExecuteAsync(OperationContext operation
}
}

internal BsonDocument CreateCommand(ConnectionDescription connectionDescription, ICoreSession session)
internal BsonDocument CreateCommand(OperationContext operationContext, ICoreSession session, ConnectionDescription connectionDescription)
{
var readConcern = ReadConcernHelper.GetReadConcernForCommand(session, connectionDescription, _readConcern);
var command = new BsonDocument
{
{ "aggregate", _collectionNamespace == null ? (BsonValue)1 : _collectionNamespace.CollectionName },
{ "pipeline", new BsonArray(_pipeline) },
{ "allowDiskUse", () => _allowDiskUse.Value, _allowDiskUse.HasValue },
{ "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue },
{ "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue && !operationContext.IsRootContextTimeoutConfigured() },
{ "collation", () => _collation.ToBsonDocument(), _collation != null },
{ "hint", _hint, _hint != null },
{ "let", _let, _let != null },
Expand All @@ -354,10 +354,10 @@ internal BsonDocument CreateCommand(ConnectionDescription connectionDescription,

private IDisposable BeginOperation() => EventContext.BeginOperation(null, "aggregate");

private ReadCommandOperation<AggregateResult> CreateOperation(RetryableReadContext context)
private ReadCommandOperation<AggregateResult> CreateOperation(OperationContext operationContext, RetryableReadContext context)
{
var databaseNamespace = _collectionNamespace == null ? _databaseNamespace : _collectionNamespace.DatabaseNamespace;
var command = CreateCommand(context.Channel.ConnectionDescription, context.Binding.Session);
var command = CreateCommand(operationContext, context.Binding.Session, context.Channel.ConnectionDescription);
var serializer = new AggregateResultDeserializer(_resultSerializer);
return new ReadCommandOperation<AggregateResult>(databaseNamespace, command, serializer, MessageEncoderSettings)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2013-present MongoDB Inc.
/* Copyright 2010-present MongoDB Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -157,7 +157,7 @@ public BsonDocument Execute(OperationContext operationContext, IWriteBinding bin
using (var channel = channelSource.GetChannel(operationContext))
using (var channelBinding = new ChannelReadWriteBinding(channelSource.Server, channel, binding.Session.Fork()))
{
var operation = CreateOperation(channelBinding.Session, channel.ConnectionDescription, mayUseSecondary.EffectiveReadPreference);
var operation = CreateOperation(operationContext, channelBinding.Session, channel.ConnectionDescription, mayUseSecondary.EffectiveReadPreference);
return operation.Execute(operationContext, channelBinding);
}
}
Expand All @@ -172,12 +172,12 @@ public async Task<BsonDocument> ExecuteAsync(OperationContext operationContext,
using (var channel = await channelSource.GetChannelAsync(operationContext).ConfigureAwait(false))
using (var channelBinding = new ChannelReadWriteBinding(channelSource.Server, channel, binding.Session.Fork()))
{
var operation = CreateOperation(channelBinding.Session, channel.ConnectionDescription, mayUseSecondary.EffectiveReadPreference);
var operation = CreateOperation(operationContext, channelBinding.Session, channel.ConnectionDescription, mayUseSecondary.EffectiveReadPreference);
return await operation.ExecuteAsync(operationContext, channelBinding).ConfigureAwait(false);
}
}

public BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescription connectionDescription)
public BsonDocument CreateCommand(OperationContext operationContext, ICoreSessionHandle session, ConnectionDescription connectionDescription)
{
var readConcern = _readConcern != null
? ReadConcernHelper.GetReadConcernForCommand(session, connectionDescription, _readConcern)
Expand All @@ -189,7 +189,7 @@ public BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescript
{ "pipeline", new BsonArray(_pipeline) },
{ "allowDiskUse", () => _allowDiskUse.Value, _allowDiskUse.HasValue },
{ "bypassDocumentValidation", () => _bypassDocumentValidation.Value, _bypassDocumentValidation.HasValue },
{ "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue },
{ "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue && !operationContext.IsRootContextTimeoutConfigured() },
{ "collation", () => _collation.ToBsonDocument(), _collation != null },
{ "readConcern", readConcern, readConcern != null },
{ "writeConcern", writeConcern, writeConcern != null },
Expand All @@ -202,9 +202,9 @@ public BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescript

private IDisposable BeginOperation() => EventContext.BeginOperation("aggregate");

private WriteCommandOperation<BsonDocument> CreateOperation(ICoreSessionHandle session, ConnectionDescription connectionDescription, ReadPreference effectiveReadPreference)
private WriteCommandOperation<BsonDocument> CreateOperation(OperationContext operationContext, ICoreSessionHandle session, ConnectionDescription connectionDescription, ReadPreference effectiveReadPreference)
{
var command = CreateCommand(session, connectionDescription);
var command = CreateCommand(operationContext, session, connectionDescription);
var operation = new WriteCommandOperation<BsonDocument>(_databaseNamespace, command, BsonDocumentSerializer.Instance, MessageEncoderSettings);
if (effectiveReadPreference != null)
{
Expand Down
Loading