簡體   English   中英

長期運行的ASP.NET任務

[英]Long-running ASP.NET tasks

我知道有很多API可以做到這一點,但是我也知道托管環境(即ASP.NET)對在單獨的線程中可以可靠地執行的操作施加了限制。

我可能完全錯了,所以如果我是我,請糾正我,但這是我認為我知道的。

  • 請求通常在120秒后超時(這是可配置的),但是最終ASP.NET運行時將終止耗時太長的請求。
  • 托管環境(通常為IIS)采用流程回收,並且可以隨時決定回收您的應用程序。 發生這種情況時,所有線程都會中止,應用程序將重新啟動。 但是我不確定它的攻擊性如何,以為它會中止正常的正在進行的HTTP請求會很愚蠢,但是我希望它會中止線程,因為它對工作單元一無所知一個線程。

如果必須創建一個編程模型,該模型可以輕松,可靠地從理論上執行一項長期運行的任務,而該任務必須運行數天,那么如何在ASP.NET應用程序中完成此任務?

以下是我對此問題的看法:

我一直在考慮在win32服務中托管WCF服務的路線很長。 並通過WCF與服務對話。 但是,這不是很實用,因為我選擇這樣做的唯一原因是要從多個不同的Web應用程序發送任務(工作單元)。 然后,我最終會向服務請求狀態更新並采取相應的措施。 我對此最大的擔心是,如果我必須將每個任務部署到服務以使其能夠執行一些指令,那將不是特別好的體驗。 還有一個輸入問題,如果我有大數據集並需要仔細檢查,該如何向該服務提供數據?

我現在通常要做的是

SELECT TOP 10 * 
FROM WorkItem WITH (ROWLOCK, UPDLOCK, READPAST)
WHERE WorkCompleted IS NULL

它允許我將SQL Server數據庫用作工作隊列,並定期使用此查詢查詢數據庫以進行工作。 如果工作項成功完成,則將其標記為已完成,然后繼續進行直到沒有其他事情要做。 我不喜歡的是,理論上我可能會在任何時候被打斷,如果我介於成功和將其標記為完成之間,那么我可能會兩次處理相同的工作項目。 我可能有點偏執,可能還不錯,但據我了解,無法保證不會發生...

我知道在SO上也有類似的問題,但實際上並沒有確切的答案。 這是很平常的事情,但是ASP.NET托管環境不具備處理長時間運行的工作的能力。

請分享您的想法。

看看NServiceBus

NServiceBus是.NET的開放源代碼通信框架,內置對發布/訂閱和長時間運行的過程的支持。

這是一項基於MSMQ的技術,這意味着您的消息不會丟失,因為它們會保存在磁盤上。 盡管如此,該框架仍具有令人印象深刻的性能和直觀的API。

約翰,

我同意ASP.NET不適合您描述的異步任務,也不應該。 它被設計為網絡托管平台,而不是內部處理器。

過去我們有過類似的情況,我們使用的解決方案與您描述的類似。 總之,將WCF服務保留在ASP.NET下,將帶有Windows服務的“隊列”表用作“ QueueProcessor”。 客戶端應進行輪詢以查看工作是否完成(或使用消息傳遞來通知客戶端)。

我們使用了一個包含流程及其信息的表(例如InvoicingRun)。 該表上有一個狀態(正在等待,正在運行,已完成,失敗)。 客戶將提交狀態為Pending的新InvoicingRun。 Windows服務(處理器)將輪詢數據庫以獲取掛起階段中的任何運行(您也可以使用SQL Notification,這樣就不需要輪詢。如果找到了掛起的運行,它將使其移至運行狀態,進行處理,然后將其移至完成/失敗。

如果進程致命失敗(例如,數據庫關閉,進程被終止),則運行將處於運行狀態,並且需要人工干預。 如果該過程在非致命狀態(異常,錯誤)下失敗,則該過程將移至失敗,並且您可以選擇重試或進行人工干預。

如果有多個處理器,則第一個將其移至運行狀態的處理器就可以完成這項工作。 您可以使用此方法來防止作業運行兩次。 替代方法是進行選擇,然后更新為在事務下運行。 確保這些事務之外的任何一個都可以進行更大的事務。 示例(粗略)SQL:

UPDATE InvoicingRun
SET Status = 2 -- Running
WHERE ID = 1
    AND Status = 1 -- Pending

IF @@RowCount = 0
    SELECT Cast(0 as bit)
ELSE
    SELECT Cast(1 as bit)

是否考慮過使用Workflow Foundation代替您的自定義實現? 它還允許您保留狀態。 在這種情況下,可以將任務定義為工作流。

只是一些想法...

麥可

使用簡單的后台任務/作業框架(例如Hangfire),並將這些最佳實踐原則應用於其余解決方案的設計中:

  • 保持所有動作盡可能小; 為此,您應該-
  • 將長期運行的作業分為幾批並排隊(在Hangfire隊列中或在另一種總線上)
  • 確保您的小型作業(長期作業的分支部分)是冪等的(具有按任何順序運行所需的所有上下文)。 這樣,您不必使用維護序列的quete。 因為那樣你就可以
  • 並行執行隊列中作業的執行,具體取決於Web服務器場中有多少個節點。 您甚至可以控制服務器場承受的負載(作為服務Web請求的折衷方案)。 這樣可確保您盡可能快速,高效地完成整個工作(所有批次),而不會影響為Web客戶端提供服務的群集。

暫無
暫無

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

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