Retry doesn't work for gridfs

I catch MongoNotPrimaryException when I use FindOne on MongoGridFS during a replica set election. I expected that driver will retry read request. https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver.Core/Core/Operations/RetryableReadOperationExecutor.cs#L93
In fact, retry works for ordinary collection but not for gridfs. It seems it is because MongoGridFS use _server.RequestStart which in turn use ChannelReadWriteBinding while ordinaty collection use WritableServerBinding (in case ReadPreferenceMode.Primary)

It is bug or intented behavior? What need to be done for retrying?

driver version: 2.11.6.0

stack trace:

MongoDB.Driver.MongoNotPrimaryException: Server returned not master error.
   at MongoDB.Driver.Core.Operations.RetryableReadOperationExecutor.Execute[TResult](IRetryableReadOperation`1 operation, RetryableReadContext context, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.ReadCommandOperation`1.Execute(RetryableReadContext context, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.FindCommandOperation`1.Execute(RetryableReadContext context, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.FindOperation`1.Execute(RetryableReadContext context, CancellationToken cancellationToken)
   at MongoDB.Driver.Core.Operations.FindOperation`1.Execute(IReadBinding binding, CancellationToken cancellationToken)
   at MongoDB.Driver.DefaultLegacyOperationExecutor.ExecuteReadOperation[TResult](IReadBinding binding, IReadOperation`1 operation, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollection.ExecuteReadOperation[TResult](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference)
   at MongoDB.Driver.MongoCursor`1.GetEnumerator(IClientSessionHandle session)
   at MongoDB.Driver.MongoCollection.UsingImplicitSession[TResult](Func`2 func)
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at MongoDB.Driver.GridFS.MongoGridFS.FindOne(IMongoQuery query, Int32 version)

Hi @111518 and welcome in the MongoDB Community :muscle: !

Your cluster must be 3.6 or above. If you are 3.6.X or 4.0.X, your URI must make it explicit that you want to use retryable reads: retryReads=true. Clusters 4.2.X and above will automatically enable retryable reads (and writes for that matter).

Also note that MongoDB 3.6 isn’t supported anymore so if you are not at 4.0 at least, it’s time to level up :mushroom:.

I’m guessing you are using C# here. So your driver version should be at least compatible with 4.2 so apparently 2.9 or above which seems to be the case here but an upgrade to 2.12 wouldn’t hurt :slight_smile:.

Finally─according to the doc─you need to use Collection.find which is apparently the only operation in GridFS that supports retryable reads. I’m not sure findOne is covered by this feature…

Source: https://docs.mongodb.com/manual/core/retryable-reads/#retryable-read-operations

Finally, I think there is an even easier solution for this issue: readPreference.

By default, your MongoDB driver reads with the read preference Primary. It means that if you don’t have a primary (which, indeed, is briefly the case during an election) then you can set your readPreference to primaryPreferred which would allow the driver to fall back on a secondary for some read operations during this brief period. In this case, you are accepting the eventual consistency of the data (as you are reading from secondaries) but as soon as the primary is back, you will go back to read on the (new) primary.

I hope this helps :smiley:.

Cheers,
Maxime.

Yes, I am using C#, mongodb 4.2. I want readPreference primary only

It seems that availability of retries depends on method. Find supports retries, findOne doesn’t. For me, it qis quite confusing behaviour because method’s names don’t tell anything about it and documentation as well. I also use writes and it seems that driver doesn’t support retryabe writes for gridfs. So I think I will catch such exceptions and retry by myself in my code.