簡體   English   中英

通過 REST 請求啟動運行時間極長的進程

[英]Start extremely long running processes through a REST request

我在一家自動化公司工作,所以我們為工業自動化創建流程。 以前這種自動化是在機器方面完成的,但我們正在慢慢過渡到使用 c# 控制機器。

在我目前的項目中,一天的制作大約需要 2 個小時。 工廠的操作員有一個我們在 c# 中使用 asp.net 核心 MVC 創建的 Web 界面,他們可以在其中啟動/暫停/停止此生產過程。

當開始這個過程時,我們等待控制器中的一個函數,它基本上是一個控制這個 2 小時長的生產過程的 while 循環。

現在的問題是,當我發出 REST 請求以開始生產時,此請求需要 2 小時才能完成,我希望此請求立即完成,並且生產過程在我的 asp.net 核心應用程序的后台開始。

首先,我想我可以省略等待,只需在我的控制器中執行此操作(簡化代碼):

_ = _productionController.StartLongProcess(); // This contains the while loop
return Ok();

但是由於 _productionController 是有作用域的,並且它的所有依賴項也是如此,因此當方法返回時這些會立即被處理掉,例如我無法再訪問我的數據庫。

該流程應該能夠不斷地與我們的數據庫對話,以保存有關生產流程的信息,以防萬一出現故障,這樣我們就可以從中斷的地方繼續進行。

我現在要問你的問題是,我們是否以錯誤的方式解決這個問題? 我想在 asp.net 控制器中啟動這些長時間運行的進程是不好的做法。

即使 REST 請求已經結束,我如何確保在這個長時間運行的過程中始終可以訪問我的 DatabaseContext。 僅為此方法創建單獨的范圍?

從 ASP.NET Core 2.1 開始,執行此操作的正確方法(在 asp.net 中)是擴展BackgroundService (或實現IHostedService )。

傳入的請求可以告訴后台服務啟動長時間運行的操作並立即返回。 您當然需要處理在現有請求完成之前發送重復請求或發送新請求的情況。

文檔頁面有一個示例,其中BackgroundService讀取隊列的命令並一次處理一個。

即使 REST 請求已經結束,我如何確保在這個長時間運行的過程中始終可以訪問我的 DatabaseContext。 僅為此方法創建單獨的范圍?

是的,創建一個單獨的范圍。

我現在要問你的問題是,我們是否以錯誤的方式解決這個問題? 我想在 asp.net 控制器中啟動這些長時間運行的進程是不好的做法。

我們過去做過類似的事情。 只要容錯(尤其是 wrt 應用程序重新啟動)和冪等性內置到長時間運行的操作的邏輯中,您就應該很高興。

REST 請求預計很短,最多幾秒鍾。 所以這里的最佳實踐是將長時間運行的任務卸載到后台服務,並返回一個令牌,如果操作已經完成,您可以在其中輪詢服務。

后台服務可以是 Net Core 中的 BackGroundWorker。 這很容易,但不是真正的容錯,所以某種數據庫和重試邏輯可能是好的。

如果您在 Intranet 中,您還可以轉而使用固有的異步協議,例如 RabbitMQ,您可以在其中發送 StartOperation 消息,然后在流程完成時接收 Started 消息。

以下是我對您發布的問題的理解:

  1. 您想通過 Rest api 調用發起長時間運行的調用
  2. 您想使用異步調用,但不確定如何為長時間運行的調用維護數據庫上下文,該調用在操作期間定期用於數據庫通信

幾個要點:

  1. 大多數情況下,您不清楚異步調用的工作
  2. 當您進行 Async 調用時,它使用狀態機存儲當前線程同步上下文以保持連續性,它不會阻塞任何線程池線程,它利用基於硬件的並發性
  3. 可以在后端使用ConfigureAwait(false)避免在當前同步上下文中顯式重入,這對性能更好
  4. 只有通過 Async 調用才能挑戰真正的 async 整個鏈需要從入口點啟用 Async,否則無法獲得好處,如果您在任何地方使用Task.WaitTask.ResultTask.Result甚至可能導致死鎖ASP.NET

關於長時間運行的操作,以下是選項

  1. 上面建議的簡單異步調用,雖然它可以幫助您進行大量異步調用(因此可擴展性),但是如果客戶端消失並且無法恢復操作狀態,上下文將丟失
  2. 您可以進行即發即棄調用,並使用像 ASP.Net SignalR 這樣的機制,它類似於網絡上的IObservable ,可以幫助在處理完成時通知客戶端
  3. 最好的選擇是使用像 Rabbit MQ 這樣的消息隊列,它不會冒客戶端宕機的風險,它充當生產者消費者並且可以在客戶端出現時通知,在這種情況下,MQ 可以在進程完成時得到通知,並且因此可以通知客戶。 MQ 可以異步方式用於傳入和響應消息

如果客戶端想要定期上來並檢查請求的狀態,那么數據庫持久性很重要,它可以定期更新,並且可以檢查長時間運行的進程的狀態。

另一種選擇是使用 Hangfire。 它將允許您將要執行的工作排入持久存儲,例如 SQL Server、MSMQ、Redis,具體取決於您的基礎架構中的內容。 然后,該作業將由一個也可以在 ASP.NET 進程或 Windows 服務中運行的工作人員接手。 它也是分布式的,因此您可以運行多個工作程序實例。 還支持重試失敗的作業,並有一個儀表板來查看作業。 最棒的是,它是免費的!

var jobId = BackgroundJob.Enqueue(() => ExecuteLongRunningProcess(parameter1));

https://www.hangfire.io/

我現在要問你的問題是,我們是否以錯誤的方式解決這個問題? 我想在 asp.net 控制器中啟動這些長時間運行的進程是不好的做法。

一般來說,是的。 理想情況下,ASP.NET 服務內部沒有任何長時間運行的進程 - 或者至少,沒有無法輕松快速關閉的長時間運行進程。

通過添加具有單獨后台處理器的持久隊列,最可靠地實現 HTTP 請求之外的工作(即請求外部代碼)。 “后台處理器”可以是 Win32 服務,甚至可能在同一台機器上。 在這種架構下,HTTP 請求將請求放入隊列,處理器從隊列中選取請求並執行它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM