Подтвердить что ты не робот

RavenDb: форсировать индексы до тех пор, пока не будет устаревать при модульном тестировании

При модульном тестировании с RavenDb часто бывает, что вновь добавленные данные извлекаются или обрабатываются иным образом. Это может привести к исключениям "устаревших индексов", например,

Bulk operation cancelled because the index is stale and allowStale is false

В соответствии с рядом ответов

Чтобы заставить базу данных (экземпляр IDocumentStore) дождаться, пока ее индексы не будут устаревшими до обработки запроса или пакетной операции, следует использовать DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites во время инициализации IDocumentStore, например:

public class InMemoryRavenSessionProvider : IRavenSessionProvider
{
    private static IDocumentStore documentStore;

    public static IDocumentStore DocumentStore
    {
        get { return (documentStore ?? (documentStore = CreateDocumentStore())); }
    }

    private static IDocumentStore CreateDocumentStore()
    {
        var store = new EmbeddableDocumentStore
        {
            RunInMemory = true,
            Conventions = new DocumentConvention
            {
                DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites,
                IdentityPartsSeparator = "-"
            }
        };
        store.Initialize();
        IndexCreation.CreateIndexes(typeof (RavenIndexes).Assembly, store);
        return store;
    }

    public IDocumentSession GetSession()
    {
        return DocumentStore.OpenSession();
    }
}

К сожалению, код выше не работает. Я все еще получаю исключения относительно устаревших индексов. Они могут быть решены путем ввода фиктивных запросов, которые включают .Customize(x => x.WaitForNonStaleResultsAsOfLastWrite()).

Это нормально, если они могут содержаться в Unit Test, но что делать, если они не могут? Я нахожу, что эти вызовы WaitForNonStaleResults* ползут в производственный код, чтобы я мог пройти модульные тесты.

Итак, есть ли верный путь огня, используя последнюю версию RavenDb, чтобы заставить индексы обновляться, прежде чем разрешать обработку команд - только для целей модульного тестирования?

Изменить 1

Вот решение, основанное на приведенном ниже ответе, заставляет ждать, пока индекс не будет устаревшим. Я написал это как метод расширения для удобства модульного тестирования;

public static class IDocumentSessionExt
{
    public static void ClearStaleIndexes(this IDocumentSession db)
    {
        while (db.Advanced.DatabaseCommands.GetStatistics().StaleIndexes.Length != 0)
        {
            Thread.Sleep(10);
        }
    }
}

И вот Unit Test, который использовал метод verbose WaitForNonStaleResultsAsOfLastWrite, но теперь использует метод расширения neater.

[Fact]
public void Should_return_list_of_Relationships_for_given_mentor()
{
    using (var db = Fake.Db())
    {
        var mentorId = Fake.Mentor(db).Id;
        Fake.Relationship(db, mentorId, Fake.Mentee(db).Id);
        Fake.Relationship(db, mentorId, Fake.Mentee(db).Id);
        Fake.Relationship(db, Fake.Mentor(db).Id, Fake.Mentee(db).Id);

        //db.Query<Relationship>()
        //  .Customize(x => x.WaitForNonStaleResultsAsOfLastWrite())
        //  .Count()
        //  .ShouldBe(3);

        db.ClearStaleIndexes();
        db.Query<Relationship>().Count().ShouldBe(3);
        MentorService.GetRelationships(db, mentorId).Count.ShouldBe(2);
    }
}
4b9b3361

Ответ 1

Если у вас есть индекс Map/Reduce, DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites не будет работать. Вам нужно использовать альтернативный метод.

В ваших модулях тесты вызывают код, подобный этому, сразу после того, как вы вставили какие-либо данные, это заставит индексы all обновиться, прежде чем вы сделаете что-нибудь еще:

while (documentStore.DatabaseCommands.GetStatistics().StaleIndexes.Length != 0)
{
    Thread.Sleep(10);
}

Обновление. Вы можете, конечно, поместить его в метод расширения, если хотите:

public static class IDocumentSessionExt
{
    public static void ClearStaleIndexes(this IDocumentSession db)
    {
        while (db.Advanced.DatabaseCommands.GetStatistics().StaleIndexes.Length != 0)
        {
            Thread.Sleep(10);
        }
    }
}

Затем вы можете сказать:

db.ClearStaleIndexes();

Ответ 2

Фактически вы можете добавить прослушиватель запросов в DocumentStore, чтобы ждать нестатистических результатов. Это можно использовать только для модульных тестов, как в хранилище документов, а не для каждой операции.

// Initialise the Store.
var documentStore = new EmbeddableDocumentStore
                {
                    RunInMemory = true
                };
documentStore.Initialize();

// Force queries to wait for indexes to catch up. Unit Testing only :P
documentStore.RegisterListener(new NoStaleQueriesListener());

....


#region Nested type: NoStaleQueriesListener

public class NoStaleQueriesListener : IDocumentQueryListener
{
    #region Implementation of IDocumentQueryListener

    public void BeforeQueryExecuted(IDocumentQueryCustomization queryCustomization)
    {
        queryCustomization.WaitForNonStaleResults();
    }

    #endregion
}

#endregion

(Бесстыдно украден из RavenDB как очистить?)

Ответ 3

Имейте в виду, что StaleIndexes также включает индексированные и отключенные индексы, которые никогда не будут обновляться.

Итак, чтобы избежать ожидания неопределенно использовать это свойство вместо:

 var staleIndices = store.DatabaseCommands.GetStatistics().CountOfStaleIndexesExcludingDisabledAndAbandoned;