2016-02-04 18 views
1

簡短的問題:假設一個非冪等的後期操作,你如何保護你的發佈請求處理程序在多次調用node.js之前,他們可以響應,從而導致數據損壞?防止在Node.js中快速調用非冪等後期操作?

具體案例:我有一個匹配的API,大約需要2-3秒才能返回(由於必須通過大型用戶庫)。有許多操作,用戶可以在同一秒內雙擊這個操作(這是一個錯誤,但不在我的控制之下,因此回答這一部分並不構成對根問題的答案)。在這些條件下,爲用戶選擇了多個匹配,這是不可取的。對於所有這些快速請求,希望得到的結果是相同的最終結果。

具體約束:

  • 的node.js /快遞/ sequelize。

  • 如果我們添加一個隊列,每個用戶的請求都將超出所有其他用戶的請求,這可能在流量過大時產生嚴重影響。

回答

1

您可以將所有請求推送到queue。在這種情況下,您的所有回覆都必須等待前面的結果。

另一種解決方案是使用後續處理事務,但這會導致數據庫中出現lock_wait_timeout錯誤。

+0

這是如何防止後端的雙重處理?隊列將包含雙重請求,並且它們都將最終執行。相反,相同的請求不應該被處理多次。 – philk

1

嘗試使用transaction。 如果你把所有的SQL命令放到一個事務中,我認爲請求會被分開。

0

在我的API下,我使用express-jwt和基於令牌的身份驗證來進行所有REST身份驗證。我保持這些令牌只對一個請求有效。一旦使用的令牌將被列入黑名單。

所以,即使您的客戶發出多個請求,只有第一個會被接受。其他人可以拋出錯誤409 Conflict。一旦處理完第一個請求,新的API令牌將與響應一起發回,可能位於標題中。

您的客戶必須不斷更新每個響應中的令牌。如果你正在使用的客戶端這就是很容易AngularJS使用interceptors

0

我看中了該解決方案最終是在@費斯托的一般方法的變化,具體如下:

  • 加入了獨特的鍵約束的比賽
  • 每個並行請求嘗試創建新的匹配;所有,但第一個將不這樣做,由於約束
  • 如果約束插入失敗,應用程序只是拉了比賽已經在數據庫中,它增加了比賽的其餘部分,並返回

這使得垃圾郵件無法通過快速調用API來創建新匹配。然而,我對此並不滿意,因爲這種方法並沒有推廣到例如:非確定性冪等操作(例如,如果匹配會隨機產生,隨後的調用將返回不同的匹配,因此簡單的約束檢查將是不足的)。

我的所有互聯網點都不回答客戶端票務管理(@Sushant),也不需要排隊,並且可以處理非確定性冪等函數。

2

我提出了一個解決方案,服務器對same*請求進行了適當的響應,因此不需要對客戶端進行任何更改。

*首先我們需要確定什麼構成一個請求被視爲「相同」。當您計劃這種優雅,同步,響應時,您會將增加的計數器放入客戶端請求中,並且此計數器是將請求定義爲same的唯一屬性。但由於您可能無法訪問客戶端並且沒有此類計數器,因此如果它們的post -body + url是相同的(並且可能導致用戶需要相同),則可以將請求定義爲相同。

因此,每個用戶在到達服務器時立即保存請求。一個簡單的方法是散列url + post -body,例如SHA-256並將其保存在如下對象中: requests[user][hashOfRequest] = null 當您的服務器計算出它時,null將被替換爲響應對象。現在處理請求。

如果客戶再次發送same*請求,您可以通過檢查您的requests[user][hashOfRequest]輕鬆找出結果。 如果服務器已完成處理,它將包含一個響應對象,您只需將其發送回客戶端。如果它仍然是空的,你需要等待你的服務器(第一個請求的)處理完成。也許使用事件偵聽器或其他任務同步模式。

服務器完成第一個請求後,它將生成response並將其保存在requests[user][hashOfRequest]=response中併發出該事件,以便潛在的等待客戶端也可以獲得響應。

沒有更多的雙重處理和連接從客戶端,其中響應沒有達到他們,也是由這種模式處理。

當然,您應該在適合您的(客戶端)場景後清理響應哈希表。也許10分鐘後,請求被放入哈希表。