1

我有這種情況下,我有一個WebApi和一個端點,當被觸發時做了很多工作(大約2-5分鐘)。這是一個帶有副作用的POST端點,我想限制執行,以便如果發送2個請求到這個端點(不應該發生,但是比對不起更安全),其中一個請等待以避免競爭條件。如何在WebApi操作中鎖定長時間的異步調用?

我第一次嘗試使用一個簡單的靜態鎖控制器內是這樣的:

lock (_lockObj) 
{ 
    var results = await _service.LongRunningWithSideEffects(); 
    return Ok(results); 
} 

這是因爲lock語句內await的當然是不可能的。

我考慮的另一個解決方案是使用一個SemaphoreSlim實現這樣的:

await semaphore.WaitAsync(); 
try 
{ 
    var results = await _service.LongRunningWithSideEffects(); 
    return Ok(results); 
} 
finally 
{ 
    semaphore.Release(); 
} 

然而,根據MSDN:

的SemaphoreSlim類表示可用於重量輕,快速旗語等待時間在之間,等待時間預計會很短

由於在這種情況下,等待時間甚至可能會達到5分鐘,我應該如何使用併發控制?

EDIT(響應plog17):

我明白,通過此任務到服務可能是最佳的方式,但是,我不一定要排隊在仍然運行在後臺的東西請求完成後。 該請求涉及需要一些時間的其他請求和集成,但我仍然希望用戶等待此請求完成並獲得響應。 這個請求預計只能在特定時間每天由cron作業觸發一次。但是,也有一個選擇可以由開發人員手動觸發它(主要是爲了防止作業出現問題),並且我想確保如果開發人員(例如,開發人員)不會遇到併發問題偶然發送請求等。

回答

1

如果在給定的時間只有一個請求可以被處理,那麼爲什麼不實施一個隊列呢?

有了這樣的設計,在處理長時間運行的請求時不再需要鎖定或等待。

流量可能是:

  1. 客戶端POST/RessourcesToProcess,應該得到迅速202接受的
  2. HttpController簡單地排隊進行任務(並返回202接受的)

  3. 其他服務(Windows服務?)出隊接下來的任務進行

  4. 繼續任務
  5. 更新資源狀態

在這個過程中,客戶端應該能夠輕鬆獲得以前的請求的狀態:

  • 如果任務不發現:404-NotFound。找不到id的資源123
  • 如果任務處理:200-OK。 123正在處理中。
  • 如果完成任務:200-確定。處理響應。

你的控制器可能看起來像:

public class TaskController 
{ 

    //constructor and private members 

    [HttpPost, Route("")] 
    public void QueueTask(RequestBody body) 
    { 
     messageQueue.Add(body); 
    } 

    [HttpGet, Route("taskId")] 
    public void QueueTask(string taskId) 
    { 
     YourThing thing = tasksRepository.Get(taskId); 

     if (thing == null) 
     { 
      return NotFound("thing does not exist"); 
     } 
     if (thing.IsProcessing) 
     { 
      return Ok("thing is processing"); 
     } 
     if (!thing.IsProcessing) 
     { 
      return Ok("thing is not processing yet"); 
     } 
     //here we assume thing had been processed 
     return Ok(thing.ResponseContent); 
    } 
} 

這種設計意味着你不處理你的WebAPI內長時間運行的過程。事實上,它可能不是最好的設計選擇。如果您仍然想這樣做,你可能需要閱讀:

+0

因爲評論字數不多的,我在編輯的形式回答,請檢查更新的問題。 – valorl

相關問題