关于状态机工作流的编程方法

Posted anpengapple

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于状态机工作流的编程方法相关的知识,希望对你有一定的参考价值。

还没想好怎么写,先起了个古怪的名字。好吧,这篇文章纯属拔草之作,只讲一种大概的解决方案。
不过,我们大概得先解决掉两个概念:一个是状态机,一个是工作流。
什么是状态机?大概来说,就是我这里有一堆的状态,我在进行一项工作的时候,有一系列的状态;我要从一个状态转移到另一个状态。举个最简单的栗子:比如一个灯泡,有“开着”和“关着”两种状态。我对这个灯泡的操作是扳动开关,灯“开着”的时候,我按关灯,就到“关着”的状态;如果我再按开灯,就到了“开着”的状态。用状态转移图来表示大概是这样的:
技术分享图片
什么是工作流?所谓工作流,就是有一定的步骤和顺序,需要按顺序进行的工作。假设在工作中,我们有一个研究课题,需要公司给予一定经费上的支持,但是公司也没法保证这个研究的可行性、是否符合公司的战略目标、是否合法、是否在公司的财务预算之内等等一系列问题,需要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使用方法的文章,官网的介绍也是比较全面的,需要用到什么去查就好了。
 

以上是关于关于状态机工作流的编程方法的主要内容,如果未能解决你的问题,请参考以下文章

几个关于js数组方法reduce的经典片段

几个关于js数组方法reduce的经典片段

嵌入式编程之状态机

Verilog 语言,关于状态机的困惑

嵌入式状态机编程-QP状态机框架与常见状态机方法

PLC状态机编程第一篇-状态机介绍