業務系統中資源爭奪情況是不存在的 - udidahan

banq發表於2022-02-08

一旦你學會用業務眼光去看,就不會有任何需要用多執行緒同步鎖實現的競賽條件了。

比方說,以下是需求。

  • 1. 如果訂單已經發貨了,不要讓使用者取消訂單。
  • 2. 如果訂單已經被取消,不要讓使用者運送訂單。

這裡的競賽條件是當我們有兩個使用者在看同一個訂單,這個訂單既沒有取消也沒有發貨,並且每個人都提交了一個命令:一個是發貨,另一個是取消訂單。

在這些情況下,程式碼很簡單:只是在執行相關命令前的一個if語句。

時間上的微秒差異不應該對核心業務行為產生影響。這意味著我們實際上在這裡得到的是需求中的一個錯誤。

使用者實際上在這裡支配著解決方案而不是需求。

 

與使用者對話

讓我們問問我們的利益相關者,"為什麼我們不應該讓使用者取消已發貨的訂單?我的意思是,使用者並不想要這些產品"。

而利益相關者會回答說:"好吧,那我們也不想退還使用者的錢。或者,至少,不是他們所有的錢。好吧,也許如果他們用原包裝退回產品,*那麼*我們可以全額退款。"

隨著我們的深入研究,"什麼時候需要退款?馬上,在同一筆交易中?"

利益相關者會解釋說,"不,退款不需要立即返回。"

 

事實證明,我們忽略了退款的概念,以及假設所有事情都需要立即處理和執行。

一旦我們深入研究了這些需求,我們發現實際上有足夠的時間讓這兩筆交易進行下去。我們只需要在交付的長期執行流程中增加一些檢查,看看訂單是否被取消,然後把這個流程縮短。

 

那麼,一切都是一個長期執行的流程嗎?

這實際上是一個公平的問題——長期執行的流程比最初看起來要普遍得多。

我們看到的是,取消現在是一個沒有理由失敗的命令——就像CQRS告訴我們的那樣。執行此命令時,它會發布計費服務訂閱的 OrderCancelled 事件。

然後計費開始一個長時間執行的過程(一個Saga,用NServiceBus術語來說),還監聽運輸過程中的事件,最終決定何時應該退款,以及退款金額。

 

更深入的業務分析

當我們與業務利益相關者更多地討論問題時,我們聽到大多數訂單實際上是在提交後一小時內被取消的。訂單在幾天後被取消的情況相當罕見。

在這種情況下,我們可以考慮把接受訂單的過程本身作為一個長期執行的流程來建模。

當使用者下訂單時,我們不會立即釋出一個表明訂單被接受的事件,而是啟動一個傳奇--這為一小時後的超時開啟了一個缺口。如果在這段時間內有取消訂單的命令到來,使用者會得到全額退款(因為我們沒有收取任何費用,因為計費沒有得到接受的事件開始),而傳奇只是關閉了自己。如果超時發生在一小時後,而傳奇沒有收到取消命令,那麼訂單實際上被接受了,事件被髮布了。

是的,Saga無處不在,一旦你學會用業務眼光去看,就不會有任何競賽條件了。

最後說一下

任何時候,當你看到表明存在競賽條件的需求時,請深入挖掘。

你有可能發現的是一些額外的業務概念以及時間的引入和長期執行的業務流程的建立。這時的實現將從瑣碎的if語句轉變成更豐富的Saga故事。

相關文章