天天看點

關于狀态機工作流的程式設計方法

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

關于狀态機工作流的程式設計方法

什麼是工作流?所謂工作流,就是有一定的步驟和順序,需要按順序進行的工作。假設在工作中,我們有一個研究課題,需要公司給予一定經費上的支援,但是公司也沒法保證這個研究的可行性、是否符合公司的戰略目标、是否合法、是否在公司的财務預算之内等等一系列問題,需要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使用方法的文章,官網的介紹也是比較全面的,需要用到什麼去查就好了。  

轉載于:https://www.cnblogs.com/anpengapple/p/9746643.html