2014-03-26 168 views
0

我們在數據庫中有一個電子郵件隊列表。它保存的主題,HTML體,以解決,從地址等電子郵件被髮送兩次

Global.asax每間隔中,Process()函數被調用,其急件電子郵件的定數。這裏的代碼:

namespace v2.Email.Queue 
{ 
    public class Settings 
    { 
     // How often process() should be called in seconds 
     public const int PROCESS_BATCH_EVERY_SECONDS = 1; 

     // How many emails should be sent in each batch. Consult SES send rates. 
     public const int EMAILS_PER_BATCH = 20; 
    } 

    public class Functions 
    { 
     private static Object QueueLock = new Object(); 

     /// <summary> 
     /// Process the queue 
     /// </summary> 
     public static void Process() 
     { 
      lock (QueueLock) 
      { 
       using (var db = new MainContext()) 
       { 
        var emails = db.v2EmailQueues.OrderBy(c => c.ID).Take(Settings.EMAILS_PER_BATCH); 
        foreach (var email in emails) 
        { 
         var sent = Amazon.Emailer.SendEmail(email.FromAddress, email.ToAddress, email.Subject, 
                   email.HTML); 
         if (sent) 
          db.ExecuteCommand("DELETE FROM v2EmailQueue WHERE ID = " + email.ID); 
         else 
          db.ExecuteCommand("UPDATE v2EmailQueue Set FailCount = FailCount + 1 WHERE ID = " + email.ID); 
        } 
       } 
      } 
     } 

問題是,它不時地發送一封電子郵件兩次。

從上面的代碼是否有任何理由可以解釋這種雙重發送?

小試按馬修斯建議

返回時,有一個紀錄:

找到

找到

未找到

如果我用這個method to clear the context cache刪除SQL查詢後,將返回:

找到

未找到

未找到

但是仍然不知道,如果它的根本原因的問題,但。我會認爲鎖定肯定會停止雙重發送。

+0

我不熟悉如何EF緩存數據,但它可能是上下文包含緩存的數據EF不知道您的原始SQL語句可能因傷病退役的緩存。當隊列中有電子郵件時,您的「Any」語句也可能是負面優化。 – Matthew

+0

我認爲問題在於'process()'函數需要更多時間,然後執行'1sec'。導致數據首次發送的數據不會在第二個條件檢查中更新。 –

+0

@avi這就是鎖定 –

回答

1

由於Entity Framework執行其內部緩存的方式而導致的問題。

爲了提高性能,實體框架將緩存實體以避免執行數據庫命中。當你在做DbSet某些操作

實體框架將更新其緩存。

實體框架不明白您的"DELETE FROM ... WHERE ..."語句應該使緩存無效,因爲EF不是SQL引擎(並且不知道您所寫的語句的含義)。因此,爲了讓EF能夠完成其工作,您應該使用EF所理解的方法。

for (var email in db.v2EmailQueues.OrderBy(c => c.ID).Take(Settings.EMAILS_PER_BATCH)) 
{ 
    // whatever your amazon code was... 

    if (sent) 
    { 
     db.v2EmailQueues.Remove(email); 
    } 
    else 
    { 
     email.FailCount++; 
    } 
} 

// this will update the database, and its internal cache. 
db.SaveChanges(); 

在一個側面說明,你應該充分利用ORM儘可能的,它不僅將節省時間的調試,它使你的代碼更容易理解。

+0

真棒解釋和答案,非常感謝。已轉換爲DbSet方法。 –