2012-09-18 41 views
3

我有這個應用程序,第一次啓動時,在我的服務器後端(兩者具有非常不同的目的)調用2個不同的API端點。但是,這兩種方法都有一個before_filter,它使用HTTP_AUTH標頭(設備標識+ api鍵)中傳遞的信息對呼叫進行認證。2 HTTP請求同時檢查是否存在記錄,如果不存在=重複記錄

如果使用提供的標識符無法從我的設備表中找到一行,它會自動創建一個具有該標識符的新行。我的問題是,似乎有時這兩個調用是同時發生的,以至於兩個請求都沒有找到任何記錄,所以它們都創建了一個新的設備行(結果是具有相同設備標識符的重複行)。

我的身份驗證方法是這樣的:

def current_user  
    authenticate_with_http_basic do |udid, secret| 
     if secret == APP_SECRET 
      @device = Device.find_by_udid(udid) 

      if [email protected] 
       @device = Device.new 
       @device.udid = udid 
       @device.created_on = DateTime.now.utc 
      end 

      // set a bunch of properties on @device 
      @device.connected_at = DateTime.now.utc 
      @device.save 
     end 
    end 
end 
+0

UDIDs已被Apple棄用,請不要存儲它們,您應該使用GUID代替 –

+0

實際上我稱它爲udid,但實際上它是MD5編碼的MAC地址:) – samvermette

+0

[mysql insert race condition](http: //stackoverflow.com/questions/264807/mysql-insert-race-condition) – noodl

回答

8

這就是唯一索引被髮明。把一個唯一索引udid(使每UDID只有一個設備可以存在),然後你的代碼可能是這樣的(僞):

def process 
    device = Device.find 

    unless device 
    device = Device.create 
    end 

    # do your work with the device 

rescue ActiveRecord::RecordNotUnique 
    retry # this is an actual ruby keyword. It means "run this begin..end block 
     # again". In this case, there's an implicit begin..end block, which is 
     # the method body. 
end 

如果第二個工人試圖插入的設備已存在UDID ,它會得到一個錯誤,應該再次嘗試搜索。

+0

很好。將嘗試,謝謝。 – samvermette

+0

Upvote for'retry' – pduersteler

+0

'rescue'太過泛泛。如果你確定知道錯誤,只有「重試」將在第二次嘗試中消失,否則你只是在旋轉你的輪子。檢查錯誤是否是一個唯一的約束違規,並且只有這樣你才應該'重試'。 –

相關問題