分散式系統解耦模式:用事件代表時間觸發Cron計劃任務
計劃任務一般都喜歡使用Cron作業來完成,比如使用spring scheduler或Quartz,本模式推薦使用黑盒式的不可知事件替代Cron作業。
問題
許多業務流程涉及需要在將來執行的某些操作或工作或工作負載。它可以是一次性動作或重複動作,可以安排在特定日期(例如聖誕節),重複日期(月的最後一個工作日)或超時(從現在起30天)。
我們希望保持整個流程的領域邏輯在單個(微)服務中很好地隔離,因此這也是此操作的邏輯所在。但是有一小部分邏輯不在這項服務中:就是事實執行需要進行,以及何時需要進行。
Cron是最麻煩的:它只適用於重複操作,並且外部工具幾乎不能控制。在大型系統中,cron檔案可能造成巨大的混亂。更現代的解決方案允許我們透過在程式碼中呼叫API來安排使用,這樣可將邏輯移動到我們自己的服務中。但從根本上說,排程程式仍然是一個單獨的服務,但是它涉及到知識比它應該知道的會更多。使用DDD術語,我們業務流程的無所不在的語言在此服務中洩漏。我們的系統中必須有更多型別的元素和更多的可移動部件。
解決
思維轉換是:將時間流逝視為另一個領域事件,就像所有其他事件一樣。畢竟,如果我們將領域事件定義為與業務相關的事件的粒度時間點,比如下一個工作日,月或季度。
在新的設計中,cron或排程程式會定期發出普通的時間段事件,例如DayHasPassed {date}午夜事件或一個 QuarterHasPassed {year, quarter}。所有感興趣的服務都會收聽此事件。他們可以透過執行操作,增加計數器,或透過查詢某個資料庫並按日期過濾來對其做出反應,以查詢有一些工作要做的專案。
舉例
時間管理著一切,有用的示例:可計費小時,訂閱,資源使用,租賃,累積利息,付款,報告,工資,維護計劃以及所有迴圈。
在發票到期日,我們需要向客戶傳送提醒。在舊設計中,我們可以設定一個呼叫的cron作業CheckForOverdueInvoices;在新設計中,cron DayHasPassed每隔午夜就產生一次,在InvoiceDebtCollection中監聽DayHasPassed。
每當此事件到達時,InvoiceDebtCollection查詢SELECT * FROM Invoice AS i WHERE DATEDIFF(i.dueDate, NOW()) >= 30。它可以直接傳送提醒,但更好的方法是發出新InvoiceBecameOverdue事件。
現在,該服務可以收聽自己的事件併傳送提醒。其他服務也可以對InvoiceBecameOverdue 做出反應,例如調整收入預測或暫停帳戶。
時間流逝事件也可以使用在更具特定領域。納斯達克的盤前交易時間為04:00至09:30,然後是正常交易時間至16:00,盤後交易時間為20:00。假期沒有交易。服務可以為每個啟動和關閉生成事件,可以由許多感興趣的服務使用。
優點
在上面的示例中,事件日誌將顯示:
CustomerWasInvoiced DayHasPassed DayHasPassed ... InvoiceBecameOverdue ReminderWasSent AccountWasSuspended |
使用時間元素編寫業務流程測試非常優雅:
場景: If no payment is received after 15 days, we suspend the account Given CustomerWasInvoiced And DayHasPassed And DayHasPassed And (...) When DayHasPassed Then InvoiceBecameOverdue And AccountWasSuspended 場景: If payment is received in time, we do nothing Given CustomerWasInvoiced And DayHasPassed And DayHasPassed When PaymentWasMade Then Nothing |
更重要的是,這是一種很好的反應方法。當服務將命令傳送到另一個服務時,它需要知道該其他服務接受該命令。當我們所做的只是傳送通用時間事件通道時,排程程式不需要知道誰在聽,消費者應該如何反應,或者是否還有任何服務可以監聽。所有決策和領域知識都歸接收者所有。這是很好的脫鉤。
它也是時間解耦:排程程式可以將此時間通道事件放在佇列中,並且此時消費者是否可用來處理事件並不重要。儘管如此,消費者可能會停頓幾天,然後只需趕上並處理DayHasPassed佇列中的所有事件。
在事件採購中,您只需將DayHasPassed事件儲存在事件儲存中,這樣您就可以完全按照時間發生的方式回放整個歷史記錄,而不依賴於外部源。
時間事件和其他領域事件型別使用完全一樣的格式和協議,透過與其他所有內容相同的訊息傳遞基礎結構傳送它 這使得該模式在實現方面非常便宜。
弱點
原來在另一個其他地方上存在的一些領域知識:用於計算何時需要發生的域邏輯,例如“每月10日”,現在已經有效地從cron或排程程式轉移到服務中。在實踐中,這不是什麼大不了的事,因為你可以找到時間庫來為你完成工作。從好的方面來說,“除了週末,滿月期間或年度辦公室聚會期間,”每個月的第10個月“都是排程員無論如何也不會為你做的事情。
值得注意的是,您不希望將時間段事件模式用於實時系統。我們可以輕鬆地實現每年365個DayHasPassed事件,但對於處理幾分鐘或幾秒或更短時間的系統,這是不可行的。幸運的是,對於程式設計師而言,在大多數企業中,“立即”一詞意味著“在工作日結束時”,或“在本週末”,或“在事情發生的月份之後的季度結束之前” 。
相關文章
- 分散式系統中的解耦模式:概要事件 - mathiasverraes分散式解耦模式事件
- 分散式系統中的解耦模式:隔離事件層 - mathiasverraes分散式解耦模式事件
- java 定時任務 quartz 時間表示式Cron總結Javaquartz
- 使用at和cron實現任務計劃
- 分散式系統中的解耦模式:領域查詢 - mathiasverraes分散式解耦模式
- 基於 Golang 開發的分散式定時任務管理系統Golang分散式
- ECTS——使用 Golang 開發的分散式定時任務管理系統Golang分散式
- 詳解非同步任務:函式計算的任務觸發去重非同步函式
- 在 Linux 中怎麼使用 cron 計劃任務Linux
- Golang——Cron 定時任務Golang
- 分散式任務排程系統設計小結分散式
- 如何使用 cron 任務在 Linux 中計劃和自動化任務Linux
- 如何使用cron任務每隔2天在固定時間執行任務
- PowerShell管理系統計劃任務
- windows計劃任務的“等待空閒時間”已棄用Windows
- linux定時任務cron配置Linux
- 微服務解耦設計模式 - Neeraj微服務解耦設計模式
- Linux 中怎麼設定計劃任務:cron 與 anacronLinux
- 分散式系統理論基礎3: 時間、時鐘和事件順序分散式事件
- 使用 Cron4j 表示式 在 Solon 裡開發定時任務
- 排查linux 定時任務cron crontabLinux
- 函式計算非同步任務能力介紹 - 任務觸發去重函式非同步
- linux 如何建立定時任務?crontab -e 定時任務使用的時間是系統時間Linux
- 複雜任務中,流程的解耦設計解耦
- Laravel Cron 定時任務 “跳坑” 點Laravel
- DOM操作小練習-觸發事件獲取系統時間的程式碼原理事件
- 帶有分散式鎖的Go計劃任務排程器- DEV分散式Godev
- 分散式之延時任務方案解析分散式
- 19種分散式系統設計模式 - Nishant分散式設計模式
- 微服務實踐之分散式定時任務微服務分散式
- 分散式系統(三)——分散式事務分散式
- 開源分散式任務排程系統就選:DolphinScheduler分散式
- 淺談分散式任務排程系統Celery的設計與實現分散式
- Linux基礎學習-crond系統計劃任務Linux
- GO的定時器Timer 和定時任務cronGo定時器
- 分散式系統2:分散式系統中的時鐘分散式
- 淺談分散式定時任務之quartz分散式quartz
- 事件驅動系統設計之將事件檢索與事件處理解耦事件解耦