2012-04-25 42 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