3

We're running RavenDB locally in docker for automated integration tests and want it to not timeout quickly, wait for stale indices before query, wait for them after writing, just do whatever it takes to not have those tests flake.

RavenDB image: ravendb/ravendb:5.3.104-ubuntu.20.04-x64

C# Client: RavenDB.Client Version="5.4.1"

The problem: tests fail sporadically on stale indices in miliseconds enter image description here

event though the DocumentStore is configured to await for stale indices for a long time.

Here's everything that I tried so far and have in this test DocumentStore setup

    public static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(10);

    private IDocumentStore CreateDocumentStore()
    {
        var store = new DocumentStore()
        {
            Urls = new[] { RavenUrl },
            Database = TestDatabaseName,
            Conventions = new DocumentConventions
            {
                WaitForIndexesAfterSaveChangesTimeout = Constants.DefaultTimeout,
                WaitForNonStaleResultsTimeout = Constants.DefaultTimeout,
            }
        };
        ConfigureDocumentStoreConventions(store);

        store.OnBeforeQuery += (_, beforeQueryExecutedArgs) =>
        {
            beforeQueryExecutedArgs.QueryCustomization.WaitForNonStaleResults(Constants.DefaultTimeout);
        };

        store.OnSessionCreated += (_, b) =>
        {
            b.Session.WaitForIndexesAfterSaveChanges(Constants.DefaultTimeout);

            // inspired by
            // https://stackoverflow.com/a/10317242/3608449
            while (b.Session.DocumentStore.Maintenance.ForDatabase(TestDatabaseName)
                       .Send(new GetStatisticsOperation()).StaleIndexes.Length != 0)
            {
                Thread.Sleep(500);
            }
        };

        store.Initialize();

        _newDatabaseWasCreated = EnsureDatabaseExists(store, TestDatabaseName);
        if (_newDatabaseWasCreated)
        {
            SeedDefaultDocuments(store);
            Thread.Sleep(2000);
        }

        return store;
    }

    private static void ConfigureDocumentStoreConventions( IDocumentStore store)
    {
        // not sure if any of this is relevant but didn't want to leave it out in case it is
        var inflector = new Inflector.Inflector(new CultureInfo("en"));

        store.Conventions.FindCollectionName = type =>
        {
            return type.Name.EndsWith(EntityPostfix)
                ? inflector.Pluralize(type.Name.Replace(EntityPostfix, string.Empty))
                : DocumentConventions.DefaultGetCollectionName(type);
        };

        store.OnBeforeStore += (sender, args) =>
        {
            if (args.Entity is BaseStorageEntity entity)
            {
                entity.Id = Guid.Parse(args.DocumentId);
            }

            if (args.Entity is IRavenDbStoreOperations operations)
            {
                operations.OnBeforeStore();
            }
        };

        store.OnAfterConversionToEntity += (sender, args) =>
        {
            if (args.Entity is BaseStorageEntity entity)
            {
                entity.Id = Guid.Parse(args.Id);
            }
        };

        var defaultDocumentIdGenerator = store.Conventions.AsyncDocumentIdGenerator;
        store.Conventions.AsyncDocumentIdGenerator = (dbName, ent) =>
        {
            if (ent is BaseStorageEntity entity)
            {
                entity.Id = entity.Id == Guid.Empty ? Guid.NewGuid() : entity.Id;
                return Task.FromResult(entity.Id.ToString());
            }

            return defaultDocumentIdGenerator(dbName, ent);
        };

        var defaultIdentityProperty = store.Conventions.FindIdentityProperty;
        store.Conventions.FindIdentityProperty = info =>
        {
            if (info.DeclaringType.IsAssignableFrom(typeof(BaseStorageEntity)))
                return false;
            return defaultIdentityProperty(info);
        };
    }

The exception from the failing test that failed after 339ms. How do I make DocumentStore respect these configured timeouts?

System.OperationCanceledException: The operation was canceled.
   at System.Threading.CancellationToken.ThrowOperationCanceledException()
   at Sparrow.Json.JsonContextPoolBase`1.AllocateOperationContext(T& context) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Sparrow\\Json\\JsonContextPoolBase.cs:line 76
   at Raven.Server.Documents.Indexes.Index.IsStale(QueryOperationContext queryContext, Nullable`1 cutoff, List`1 stalenessReasons) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Indexes\\Index.cs:line 1192
   at Raven.Server.Documents.Handlers.BatchHandler.WaitForIndexesAsync(DocumentsContextPool contextPool, DocumentDatabase database, TimeSpan timeout, List`1 specifiedIndexesQueryString, Boolean throwOnTimeout, String lastChangeVector, Int64 lastTombstoneEtag, HashSet`1 modifiedCollections) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Handlers\\BatchHandler.cs:line 404
   at Raven.Server.Documents.Handlers.BatchHandler.BulkDocs() in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Handlers\\BatchHandler.cs:line 142
   at Raven.Server.Routing.RequestRouter.HandlePath(RequestHandlerContext reqCtx) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Routing\\RequestRouter.cs:line 365
   at Raven.Server.RavenServerStartup.RequestHandler(HttpContext context) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\RavenServerStartup.cs:line 240","data":{},"innerException":{"ClassName":"System.OperationCanceledException","Message":"System.OperationCanceledException: The operation was canceled.
   at System.Threading.CancellationToken.ThrowOperationCanceledException()
   at Sparrow.Json.JsonContextPoolBase`1.AllocateOperationContext(T& context) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Sparrow\\Json\\JsonContextPoolBase.cs:line 76
   at Raven.Server.Documents.Indexes.Index.IsStale(QueryOperationContext queryContext, Nullable`1 cutoff, List`1 stalenessReasons) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Indexes\\Index.cs:line 1192
   at Raven.Server.Documents.Handlers.BatchHandler.WaitForIndexesAsync(DocumentsContextPool contextPool, DocumentDatabase database, TimeSpan timeout, List`1 specifiedIndexesQueryString, Boolean throwOnTimeout, String lastChangeVector, Int64 lastTombstoneEtag, HashSet`1 modifiedCollections) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Handlers\\BatchHandler.cs:line 404
   at Raven.Server.Documents.Handlers.BatchHandler.BulkDocs() in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Handlers\\BatchHandler.cs:line 142
   at Raven.Server.Routing.RequestRouter.HandlePath(RequestHandlerContext reqCtx) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Routing\\RequestRouter.cs:line 365
   at Raven.Server.RavenServerStartup.RequestHandler(HttpContext context) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\RavenServerStartup.cs:line 240","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":null,"RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":null,"HResult":-2146233029,"Source":null,"WatsonBuckets":null},"helpLink":null,"source":"Raven.Client","hResult":-2146233088,"stackTrace":"   at Raven.Client.Exceptions.ExceptionDispatcher.Throw(JsonOperationContext context, HttpResponseMessage response, Action`1 additionalErrorInfo) in C:\\Builds\\RavenDB-Stable-5.4\\54001\\src\\Raven.Client\\Exceptions\\ExceptionDispatcher.cs:line 119
   at Raven.Client.Http.RequestExecutor.HandleUnsuccessfulResponse[TResult](ServerNode chosenNode, Nullable`1 nodeIndex, JsonOperationContext context, RavenCommand`1 command, HttpRequestMessage request, HttpResponseMessage response, String url, SessionInfo sessionInfo, Boolean shouldRetry, CancellationToken token) in C:\\Builds\\RavenDB-Stable-5.4\\54001\\src\\Raven.Client\\Http\\RequestExecutor.cs:line 1457
   at Raven.Client.Http.RequestExecutor.ExecuteAsync[TResult](ServerNode chosenNode, Nullable`1 nodeIndex, JsonOperationContext context, RavenCommand`1 command, Boolean shouldRetry, SessionInfo sessionInfo, CancellationToken token) in C:\\Builds\\RavenDB-Stable-5.4\\54001\\src\\Raven.Client\\Http\\RequestExecutor.cs:line 903
   at Raven.Client.Http.RequestExecutor.ExecuteAsync[TResult](ServerNode chosenNode, Nullable`1 nodeIndex, JsonOperationContext context, RavenCommand`1 command, Boolean shouldRetry, SessionInfo sessionInfo, CancellationToken token) in C:\\Builds\\RavenDB-Stable-5.4\\54001\\src\\Raven.Client\\Http\\RequestExecutor.cs:line 903
   at Raven.Client.Documents.Session.AsyncDocumentSession.SaveChangesAsync(CancellationToken token) in C:\\Builds\\RavenDB-Stable-5.4\\54001\\src\\Raven.Client\\Documents\\Session\\AsyncDocumentSession.cs:line 171
   at VendorCenter.Relationships.ItSystemRelationship.Repository.ItSystemRelationshipRepository.Update(Guid entityId, Action`1 applyChanges) in /home/runner/work/Cirrus/Cirrus/backend/src/VendorCenter/VendorCenter/VendorCenter/Relationships/ItSystemRelationship/Repository/ItSystemRelationshipRepository.cs:line 83
   at VendorCenter.Relationships.ItSystemRelationship.Features.Commands.UpdateItSystemRelationshipConsequenceCommandHandler.Handle(UpdateItSystemRelationshipConsequenceCommand request, CancellationToken cancellationToken) in /home/runner/work/Cirrus/Cirrus/backend/src/VendorCenter/VendorCenter/VendorCenter/Relationships/ItSystemRelationship/Features/Commands/UpdateItSystemRelationshipConsequenceCommand.cs:line 36
   at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
   at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
   at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
   at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
   at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
   at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken)
   at CC.Core.Shared.Mediator.Mediator.Pipelines.LoggingBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/Cirrus/Cirrus/backend/CC.Core.Shared/Mediator/Mediator/Pipelines/LoggingBehaviour.cs:line 22
   at CC.Core.Shared.Mediator.Validation.ValidationBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken cancellationToken) in /home/runner/work/Cirrus/Cirrus/backend/CC.Core.Shared/Mediator/Validation/ValidationBehavior.cs:line 33
   at VendorCenter.Relationships.ItSystemRelationship.ItSystemRelationshipsController.UpdateRelationshipConsequence(Guid relationshipId, Consequence consequence) in /home/runner/work/Cirrus/Cirrus/backend/src/VendorCenter/VendorCenter/VendorCenter/Relationships/ItSystemRelationship/ItSystemRelationshipsController.cs:line 88
   at lambda_method4045(Closure, Object)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)"},"detail":"System.OperationCanceledException: The operation was canceled.
   at System.Threading.CancellationToken.ThrowOperationCanceledException()
   at Sparrow.Json.JsonContextPoolBase`1.AllocateOperationContext(T& context) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Sparrow\\Json\\JsonContextPoolBase.cs:line 76
   at Raven.Server.Documents.Indexes.Index.IsStale(QueryOperationContext queryContext, Nullable`1 cutoff, List`1 stalenessReasons) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Indexes\\Index.cs:line 1192
   at Raven.Server.Documents.Handlers.BatchHandler.WaitForIndexesAsync(DocumentsContextPool contextPool, DocumentDatabase database, TimeSpan timeout, List`1 specifiedIndexesQueryString, Boolean throwOnTimeout, String lastChangeVector, Int64 lastTombstoneEtag, HashSet`1 modifiedCollections) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Handlers\\BatchHandler.cs:line 404
   at Raven.Server.Documents.Handlers.BatchHandler.BulkDocs() in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Documents\\Handlers\\BatchHandler.cs:line 142
   at Raven.Server.Routing.RequestRouter.HandlePath(RequestHandlerContext reqCtx) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\Routing\\RequestRouter.cs:line 365
   at Raven.Server.RavenServerStartup.RequestHandler(HttpContext context) in C:\\Builds\\RavenDB-Stable-5.3\\53029\\src\\Raven.Server\\RavenServerStartup.cs:line 240
LLL
  • 3,566
  • 2
  • 25
  • 44

0 Answers0