2012-04-25 36 views
22

使用RavenDb进行单元测试时,通常会检索或处理新增的数据。这可能导致“陈旧索引”例外,例如RavenDb:强制索引等待,直到单元测试时才失效

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

根据一些答案

迫使数据库的方式(在IDocumentStore实例)的等待,直到它的索引在处理之前不会陈旧查询或批处理操作是IDocumentStore初始化过程中使用DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites,像这样:

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())

这很好,只要这些可以包含在单元测试中,但如果它们不能?我发现这些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); 
     } 
    } 
} 

这里是已使用详细WaitForNonStaleResultsAsOfLastWrite技术单元测试,但现在使用更简洁扩展方法。

[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); 
    } 
} 
+1

现在这是举行反对DocumentStore而非DocumentSession,所以扩展方法会改变使用类似db.Advanced.DocumentStore.DatabaseCommands。 GetStatistics().StaleIndexes.Any(),或者直接将DocumentStore直接放入,如果可以的话 – adrian 2014-08-12 15:12:20

回答

27

如果你有一个的Map/Reduce指数,DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites将无法​​正常工作。你需要使用另一种方法。

在你的单位测试中,调用这样的代码,您插入任何数据直后,这将迫使所有指标更新你做任何事情之前:

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(); 
+0

我会尝试'Thread.Sleep(10)'思路。然而,我有Map索引(它们有一个map函数,但不是一个reduce函数),正是这些索引引发'Bulk operation .. index is stale'异常。 “ConsistencyOptions.QueryYourWrites”预计适用于仅限Map的索引吗? – biofractal 2012-04-25 14:05:28

+0

它应该这样做,但批量操作可能是问题。使用上面的代码来确保所有索引都是最新的(在插入文档之后和查询之前),并且您应该没问题。 – 2012-04-25 14:18:18

+1

请参阅编辑1.尽管您可能想更新您的答案以使用最新的语法,但它可以满足您的要求。封装等待作为扩展方法使得一切都很好和整洁:-) – biofractal 2012-04-25 15:02:02

14

您实际上可以在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 how to flush?无耻被盗)

+2

我试过了,它正常的'查询<>()'调用(没有陈旧的索引),但它失败了一个地图索引(无减少)通过'db调用.Advanced.DatabaseCommands.UpdateByIndex(..)'。这是预期的行为? – biofractal 2012-04-25 14:59:50

+0

Hrm,这与常规查询不同。我将不得不研究这个(或者建议要实施的东西),因为应该有一种非侵入性的方式来做到这一点。 – Rangoric 2012-04-25 15:49:06

+2

使用监听器肯定会比根据接受的答案手动调用扩展方法更好的低干预解决方案,但是到目前为止,没有一个DocumentStore级别的修补程序似乎适用于批量更新,即当我通过'UpdateByIndex使用索引时(..)'。祝你好运! – biofractal 2012-04-26 09:03:28

1

注意StaleIndexes还包括abondoned和残疾人指数 - 这永远不会是最新的。

因此,为了避免等待indefinetely使用这个属性,而不是:

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

刚刚碰到一个问题,因为StaleIndexes还包括被遗弃的人。你的方法似乎解决了它。 – Fjut 2017-11-06 09:53:34

相关问题