還沒想好怎么寫,先起了個古怪的名字。好吧,這篇文章純屬拔草之作,只講一種大概的解決方案。
不過,我們大概得先解決掉兩個概念:一個是狀態機,一個是工作流。
什么是狀態機?大概來說,就是我這里有一堆的狀態,我在進行一項工作的時候,有一系列的狀態;我要從一個狀態轉移到另一個狀態。舉個最簡單的栗子:比如一個燈泡,有“開着”和“關着”兩種狀態。我對這個燈泡的操作是扳動開關,燈“開着”的時候,我按關燈,就到“關着”的狀態;如果我再按開燈,就到了“開着”的狀態。用狀態轉移圖來表示大概是這樣的:

什么是工作流?所謂工作流,就是有一定的步驟和順序,需要按順序進行的工作。假設在工作中,我們有一個研究課題,需要公司給予一定經費上的支持,但是公司也沒法保證這個研究的可行性、是否符合公司的戰略目標、是否合法、是否在公司的財務預算之內等等一系列問題,需要A、B、C、D四個人審批,A審批通過后交給B,B通過交給C,C通過交給D,D通過才算完全通過。如果有其中某一個不通過的,就要從頭再來過。
那么狀態機工作流就比較好理解了,就是把狀態機和工作流結合在一起。還用上面那個審批的栗子,我們可以畫出這樣一個狀態轉移圖:

OK,那么常規思路怎么做呢?
def approve(): if A通過: if B通過: if C通過: if D通過: return 通過 return 不通過
用腳后跟想想也知道,這樣是行不通的。如果A審批通過,B不在線,不能馬上通過怎么辦?開個線程阻塞掉?如果C審批完了,服務器突然宕機怎么辦?前面的審批全都要重來一遍?我們這個審批流程已經是非常簡單明確了,如果狀態機再復雜一些……
對不起,代碼不是這么堆的。
那么,我的思路是這樣的:
既然最重要的是狀態轉移,那我們不妨把工作流中的每個狀態保存起來,作為一個步驟。我們可以在數據庫中單獨增加一個表示狀態的字段。比如,當狀態為1的時候,表示“需要A審批”,狀態為2的時候,表示“需要B審批”等等。表示審批的函數當然也很簡單:
def approve(): if agree: status += 1 else: status = 0 return status
接下來的工作,可能要看具體屬於哪一類型的工作流。
如果是審批這種,當然再簡單不過了,需要B審批了,我們就把數據庫中狀態為2的那些數據拿出來就好了。
有些類型不是靠前端展示的,而是后端執行的一系列動作,這樣會復雜一些。如果對時間的要求不是特別高,可以用定時任務來處理。比如,我們把ABCD四個審批者換成ABCD四個環節,那么,我們每隔一段時間,選取數據庫中尚未完成的任務,狀態為1的任務進行A環節,狀態為2的任務進行B環節,等等。
定時任務嘛,如果很簡單,可以用schedule庫,復雜一點的任務還是推薦celery——因為celery會給任務分配單獨的任務隊列和線程,操作起來比schedule要方便得多。而且需要定好大概得時間,以免任務太多,產生堆積。schedule我在之前的博文中介紹過,celery相對比較復雜,我現在也只會用其中的一部分。網上有比較完整的celery使用方法的文章,官網的介紹也是比較全面的,需要用到什么去查就好了。