天天看點

.net core實踐系列之短信服務-Sikiro.SMS.Job服務的實作

本篇會繼續講解Sikiro.SMS.Job服務的實作,在我寫第一篇的時候,我就發現我當時設計的架構裡Sikiro.SMS.Job這個可以選擇不需要,而使用MQ代替。但是為了說明排程任務使用實作也堅持寫了下。後面會一篇針對架構、實作優化的講解。

源碼位址:https://github.com/SkyChenSky/Sikiro.SMS

Quartz.NET是一款功能齊全的開源作業排程架構,小至的應用程式,大到企業系統都可以适用。Quartz是作者James House用JAVA語言編寫的,而Quartz.NET是從Quartz移植過來的C#版本。

Quartz.Net是多線程的,允許多個JOB同時執行。

Quartz.Net可以進行持久化,結合管理背景可以進行可視化的監控

Quartz.Net提供API進行遠端操控,結合管理背景可以進行運維管理

在一般企業,可以利用Quartz.Net架構做各種的定時任務,例如,資料遷移、跑報表等等。

字段名

是否必填

值範圍

特殊字元

Seconds

YES

0-59

, - * /

Minutes

Hours

0-23

Day of month

1-31

, - * ? / L W

Month

1-12 or JAN-DEC

Day of week

1-7 or SUN-SAT

, - * ? / L #

Year

NO

empty, 1970-2099

Quartz.Net的缺點很明顯,沒有自帶的管理背景,而同款的Hangfir排程任務架構則會有更加良好的易用性。但是在Github上有不少人開源了Quartz.Net的管理背景,對此作為了彌補。

其他Quartz.Net的資訊可以看我之前記錄的一篇文章《Quartz.NET的使用(附源碼)》

Quartz.Net DEMO:https://github.com/SkyChenSky/QuartzDotNetDemo.git

.net core實踐系列之短信服務-Sikiro.SMS.Job服務的實作

從MongoDB持久化的資料,查詢出狀态為待處理并且定時時間小于目前時間的資料。通過Mongo驅動提供的FindOneAndUpdate對文檔進行原子性操作(更新中間狀态并查詢出剛更新的文檔)。如果有資料則發送到MQ,由Sikiro.SMS.Bus進行訂閱發送,因為本次有資料,我認為可能還會有其他需要發送的資料,是以立刻調用JOB自身方法,進行下一條需要處理的資料進行發送。如果此次JOB的執行并沒有資料,那麼認為接下來一段時間沒有需要處理的資料,這次排程結束。

Job的輪詢處理流程基本相似,查詢出需要執行資料-周遊業務處理-如果有異常則特殊處理,是以針對類似流程相同,但是實作有差異的程式,我們可以使用模闆模式。

原子是實體概念,指的是指化學反應不可再分的基本微粒。而計算機領域的原子性強調的對象是操作(指令、事務)。我們所說的指令組是原子操作,意思要麼一起成功,要麼一起失敗。不允許2個指令裡,一個成功一個失敗的情況存在。

MongoDB的原子操作就是要麼這個文檔完整的儲存到Mongodb,要麼沒有儲存到Mongodb,不會出現查詢到的文檔沒有儲存完整的情況。

MongoDB的文檔的儲存,修改,删除等操作都是原子性,除此之外還提供了FindOneAndDelete、FindOneAndUpdate、FindOneAndReplace等原子操作。

以FindOneAndUpdate為例,對某文檔FindOneAndUpdate,可以文檔B進行Update操作完成後傳回出文檔B的結果,根據參數傳回結果是更新前還是更新後(一般我們需要更新後)。

而這FindOneAndUpdate的操作對于我們更新到中間狀态的非常實用:

避免進行Update後無法良好的查詢到剛Update的文檔

避免應用叢集部署時批量更新後,無法良好配置設定任務

批量更新多個文檔需要isolated辨別隔離,全局鎖在大并發情況下性能并不樂觀

雖然以上可以通過更新時辨別版本号進行解決,這無疑增加實作難度。

Mongodb并發操作又讀寫鎖來進行控制。

簡單來說

當進行讀操作的時候會加讀鎖,這個時候其他讀操作可以也獲得讀鎖,但是不能加寫鎖,也就是說不能進行寫操作。

當進行寫操作的時候會加寫鎖,這個時候其他操作無法加任何鎖,也就是說不能進行其他的讀操作和寫操作。

綜上所述,落實到我們應用場景,在部署多個排程任務服務,或者JOB多個線程去跑時,我們可以使用FindOneAndUpdate,每個排程任務每次隻處理一個文檔,Update操作的時候會進行寫鎖阻塞其他程序(程序)的寫操作。那麼就可以保證每個排程任務都可以隻處理唯一一個有效的文檔,避免重複處理。

下面是我的Sikiro.Nosql.Mongo的FindOneAndUpdate封裝示例,因為Update字段的不友好,是以我封裝了一下Lambda表達式,ReturnDocument = ReturnDocument.After辨別響應資料是更新前還是更新後的文檔。

SQL Server的操作也具有上述FindOneAndUpdate的功能,我們公司成他為UpdateSelect,下面是示例代碼:

本篇介紹了排程任務結合MongoDB原子操作的使用,使得排程任務服務可以具有良好的伸縮性。如果有任何建議與問題可以在下方評論回報給我。

作  者:

陳珙

出  處:http://www.cnblogs.com/skychen1218/

關于作者:專注于微軟平台的項目開發。如有問題或建議,請多多賜教!

版權聲明:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連結。

聲援部落客:如果您覺得文章對您有幫助,可以點選文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!