Flowable14定时器事件----------------持续更新中

定时器事件是流程自动化的核心工具,它允许流程在特定时间点或经过一段时间后自动触发行为。它的本质是“在未来的某个时间点做某件事”。

一、 核心作用

调度启动 (Scheduling Start):在预定的时间自动开始一个新的流程实例。例如,定时生成报表、定时清理数据等。
超时管理 (Timeout Management):为某个任务或活动设置一个期限。如果超过期限未完成,则执行备用路径。这是最常见的用途,如审批超时、付款超时。
流程延迟 (Process Delay):让流程暂停一段时间后再继续执行。例如,下单后,等待30分钟以便用户可以取消订单,30分钟后再进入发货环节。

二、 定时器事件的类型(按位置)

定时器开始事件 (Timer Start Event)
作用:作为流程的起点,由时间驱动。
场景:每天早上9点启动“日报收集流程”。
中间捕获定时器事件 (Intermediate Catching Timer Event)
作用:作为一个流程节点,当流程执行到这里时,会停下来等待,直到指定的时间条件满足。
场景:支付成功后,流程走到一个“等待24小时”的定时器事件,之后再自动确认收货。
定时器边界事件 (Timer Boundary Event)
作用:附加在某个活动(通常是用户任务)上,作为该活动的“超时监控器”。
场景:“经理审批”任务,如果超过3天未处理,定时器边界事件被触发,流程将沿着另一条路径走(例如自动批准或升级给更高层领导)。

三、 定时器定义 (Timer Definition) - 核心配置

无论哪种定时器事件,其核心都是配置一个“时间规则”。Flowable 支持标准的 BPMN 2.0 格式,主要有三种:
特定日期 (Time Date - ISO 8601)
格式:YYYY-MM-DDTHH:MM:SS
含义:在某个精确的日期和时间点触发。
示例:2025-01-01T00:00:00 表示在2025年元旦零点触发。
用途:用于一次性的、已知的未来时间点。
时间周期 (Time Duration)
格式:P[n]Y[n]M[n]DT[n]H[n]M[n]S
含义:从流程到达该节点开始,等待多长时间后触发。
P:Period(周期)的标志,必须有。
D:天 (Day)。
T:时间 (Time) 的分隔符,如果要定义时、分、秒,必须在前面加 T。
H:小时 (Hour)。
M:分钟 (Minute)。
S:秒 (Second)。
示例:
P3D:等待3天。
PT10H:等待10小时。
PT30M:等待30分钟。
P1DT12H:等待1天零12小时。
用途:最常用于超时和延迟场景。
时间循环 (Time Cycle) / Cron 表达式
含义:重复性地触发。
格式1 (ISO 8601):R[n]/ 或 R[n]//
R:Repeating(重复)的标志。
R5/PT10M:每10分钟触发一次,共触发5次。
R/P1D:从流程启动开始,每隔一天触发一次(无限次)。
格式2 (Cron 表达式 - 更常用):Flowable 扩展支持标准的 Cron 表达式。
格式:秒 分 时 日 月 周 [年] (通常省略年)
示例:0 0 9 * * ? 表示每天早上9点整触发。
0 0/15 * * * ? 表示每小时的0分、15分、30分、45分触发。
用途:最常用于定时器开始事件,实现定时任务调度。

四、 底层工作原理

创建 Job:当流程执行到一个定时器事件时,Flowable 不会阻塞主线程。它会在数据库的 ACT_RU_TIMER_JOB 表中创建一条记录(一个 Job),并记录下该 Job 的到期执行时间 (DUEDATE_)。
Job Executor:Flowable 引擎有一个后台的组件叫做 Job Executor(作业执行器),它是一个后台线程池。
轮询与执行:Job Executor 会定期扫描 ACT_RU_TIMER_JOB 表,查找所有到期时间早于或等于当前时间的 Job。
触发流程:一旦找到到期的 Job,Job Executor 就会锁定并执行它。执行 Job 的结果就是触发相应的流程行为(启动流程、中断任务等),然后删除该 Job 记录。


在 Flowable UI (Modeler) 中设计定时器事件

下面我们通过三个典型场景,一步步演示如何在 Flowable UI Modeler 中进行设计。
场景一:定时器开始事件 - “每天早上9点生成日报”
【步骤一】拖入并转换事件
从左侧工具栏拖拽一个 Start Event 到画布上。
点击这个开始事件,在弹出的快捷菜单中选择“扳手”图标(Change type)。
在类型列表中选择 Timer Start Event。你会看到圆圈图标内出现了一个时钟。
【步骤二】配置定时器属性
选中这个 Timer Start Event,右侧的 Properties 面板会自动显示其属性。
找到 Timer definition 区域。
Timer definition type: 选择 Timer cycle(因为是重复任务)。
Timer definition: 输入 Cron 表达式 0 0 9 * * ?。
这样,一个每天早上9点自动触发的流程就定义好了。后面可以接上“生成报告”、“发送通知”等任务。
场景二:定时器边界事件 - “审批任务超过3天未处理则自动通过”
【步骤一】创建基础任务
拖拽一个 User Task 到画布上,并命名为“经理审批”。
【步骤二】附加边界事件
从左侧工具栏拖拽一个 Intermediate Catching Event。
关键操作:将它拖动到“经理审批”这个 User Task 的边框上,直到边框高亮显示再松开鼠标。事件会自动吸附到任务上。
点击这个新附加的边界事件,使用“扳手”图标将其类型更改为 Timer Boundary Event。
【步骤三】配置定时器和行为
选中这个 Timer Boundary Event,查看右侧的 Properties 面板。
在 Timer definition 区域:
Timer definition type: 选择 Timer duration。
Timer definition: 输入 P3D (表示3天)。
重要属性:在 General 区域,有一个 Cancel activity 的复选框。
勾选 (默认):这是中断型。3天后,如果“经理审批”任务还未完成,它将被强制取消,流程会沿着定时器事件引出的路径继续。
不勾选:这是非中断型。3天后,即使“经理审批”任务未完成,它依然存在,同时会从定时器事件处创建一条新的并行分支。
【步骤四】设计超时后的流程
从定时器边界事件的节点,拖拽一条线连接到一个新的活动,例如一个 Script Task(脚本任务),在脚本中设置流程变量为“自动通过”,然后再连接到结束事件。
场景三:中间捕获定时器事件 - “付款后等待30分钟”
【步骤一】拖入并转换事件
假设流程中已经有一个“支付成功”的节点。
从工具栏拖拽一个 Intermediate Catching Event 到“支付成功”节点之后。
使用“扳手”图标将其类型更改为 Timer Catching Event。
【步骤二】配置定时器
选中这个 Timer Catching Event,查看右侧的 Properties 面板。
在 Timer definition 区域:
Timer definition type: 选择 Timer duration。
Timer definition: 输入 PT30M (表示30分钟)。
将此事件连接到后续的活动,如“通知仓库发货”。当流程执行到这个定时器事件时,会暂停30分钟,然后再继续。

对应BPMN文件如下,将这三个功能都穿起来了

业务场景:每日高价值订单审批流程
启动:系统在每天上午10点自动启动此流程,检查是否有待处理的高价值订单。 (使用 定时器开始事件)
审批:如果存在待处理订单,流程会创建一个“经理审批”任务。
超时:经理有2天的时间来处理这个审批任务。如果超过2天未处理,系统将自动批准该订单,并记录超时情况。 (使用 定时器边界事件)
延迟:无论经理是手动批准还是系统超时自动批准,订单在最终处理前,都需要等待30分钟。这可能是为了给系统一个缓冲时间,或者等待相关资源锁定。 (使用 中间捕获定时器事件)
完成:等待30分钟后,系统执行“最终订单处理”并结束流程。

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
             xmlns:flowable="http://flowable.org/bpmn"
             typeLanguage="http://www.w3.org/2001/XMLSchema"
             expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.flowable.org/processdef">

  <process id="combinedTimerProcess" name="每日高价值订单审批流程" isExecutable="true">

    <!-- 1. 定时器开始事件:每天上午10点触发 -->
    <startEvent id="startTimerEvent" name="每天10点开始">
      <timerEventDefinition>
        <timeCycle>0 0 10 * * ?</timeCycle>
      </timerEventDefinition>
    </startEvent>

    <sequenceFlow id="flow1" sourceRef="startTimerEvent" targetRef="checkOrdersTask"/>

    <serviceTask id="checkOrdersTask" name="检查高价值订单" flowable:expression="${execution.setVariable('orderExists', true)}"/>
    
    <sequenceFlow id="flow2" sourceRef="checkOrdersTask" targetRef="gatewayOrderExists"/>

    <exclusiveGateway id="gatewayOrderExists" name="是否有订单?"/>

    <sequenceFlow id="flowNoOrder" name="无订单" sourceRef="gatewayOrderExists" targetRef="endEventNoOrder">
        <conditionExpression xsi:type="tFormalExpression">${!orderExists}</conditionExpression>
    </sequenceFlow>
    
    <sequenceFlow id="flowHasOrder" name="有订单" sourceRef="gatewayOrderExists" targetRef="managerApprovalTask">
        <conditionExpression xsi:type="tFormalExpression">${orderExists}</conditionExpression>
    </sequenceFlow>
    
    <!-- 2. 用户任务,附加了定时器边界事件 -->
    <userTask id="managerApprovalTask" name="经理审批" flowable:candidateGroups="managers"/>
    
    <sequenceFlow id="flowApprovalDone" sourceRef="managerApprovalTask" targetRef="wait30MinTimer"/>
    
    <!-- 定时器边界事件:2天超时 -->
    <boundaryEvent id="approvalTimeoutBoundary" attachedToRef="managerApprovalTask" cancelActivity="true">
      <timerEventDefinition>
        <timeDuration>P2D</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>

    <sequenceFlow id="flowTimeout" sourceRef="approvalTimeoutBoundary" targetRef="autoApproveTask"/>
    
    <scriptTask id="autoApproveTask" name="超时自动批准" scriptFormat="groovy">
        <script>
            System.out.println("订单 " + execution.getProcessInstanceId() + " 已超时并自动批准。");
            execution.setVariable("approvalResult", "auto_approved_timeout");
        </script>
    </scriptTask>

    <sequenceFlow id="flowAfterAutoApprove" sourceRef="autoApproveTask" targetRef="wait30MinTimer"/>

    <!-- 3. 中间捕获定时器事件:等待30分钟 -->
    <intermediateCatchEvent id="wait30MinTimer" name="等待30分钟">
      <timerEventDefinition>
        <timeDuration>PT30M</timeDuration>
      </timerEventDefinition>
    </intermediateCatchEvent>

    <sequenceFlow id="flowAfterWait" sourceRef="wait30MinTimer" targetRef="finalizeOrderTask"/>
    
    <serviceTask id="finalizeOrderTask" name="最终订单处理" flowable:class="org.flowable.examples.FinalizeOrderDelegate"/>

    <sequenceFlow id="flowFinal" sourceRef="finalizeOrderTask" targetRef="endEventSuccess"/>

    <endEvent id="endEventSuccess" name="成功结束"/>
    <endEvent id="endEventNoOrder" name="无订单结束"/>

  </process>

  <bpmndi:BPMNDiagram id="BPMNDiagram_combinedTimerProcess">
    <bpmndi:BPMNPlane bpmnElement="combinedTimerProcess" id="BPMNPlane_combinedTimerProcess">
      <bpmndi:BPMNShape bpmnElement="startTimerEvent" id="BPMNShape_startTimerEvent">
        <omgdc:Bounds height="36.0" width="36.0" x="50.0" y="200.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="checkOrdersTask" id="BPMNShape_checkOrdersTask">
        <omgdc:Bounds height="60.0" width="100.0" x="130.0" y="188.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="gatewayOrderExists" id="BPMNShape_gatewayOrderExists">
        <omgdc:Bounds height="40.0" width="40.0" x="270.0" y="198.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="managerApprovalTask" id="BPMNShape_managerApprovalTask">
        <omgdc:Bounds height="60.0" width="100.0" x="350.0" y="188.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="approvalTimeoutBoundary" id="BPMNShape_approvalTimeoutBoundary">
        <omgdc:Bounds height="30.0" width="30.0" x="430.0" y="233.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="autoApproveTask" id="BPMNShape_autoApproveTask">
        <omgdc:Bounds height="60.0" width="100.0" x="480.0" y="280.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="wait30MinTimer" id="BPMNShape_wait30MinTimer">
        <omgdc:Bounds height="36.0" width="36.0" x="512.0" y="199.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="finalizeOrderTask" id="BPMNShape_finalizeOrderTask">
        <omgdc:Bounds height="60.0" width="100.0" x="600.0" y="187.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endEventSuccess" id="BPMNShape_endEventSuccess">
        <omgdc:Bounds height="36.0" width="36.0" x="740.0" y="199.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endEventNoOrder" id="BPMNShape_endEventNoOrder">
        <omgdc:Bounds height="36.0" width="36.0" x="362.0" y="290.0"/>
      </bpmndi:BPMNShape>
      
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="86.0" y="218.0"/>
        <omgdi:waypoint x="130.0" y="218.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="230.0" y="218.0"/>
        <omgdi:waypoint x="270.0" y="218.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowHasOrder" id="BPMNEdge_flowHasOrder">
        <omgdi:waypoint x="310.0" y="218.0"/>
        <omgdi:waypoint x="350.0" y="218.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowNoOrder" id="BPMNEdge_flowNoOrder">
        <omgdi:waypoint x="290.0" y="238.0"/>
        <omgdi:waypoint x="290.0" y="308.0"/>
        <omgdi:waypoint x="362.0" y="308.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowApprovalDone" id="BPMNEdge_flowApprovalDone">
        <omgdi:waypoint x="450.0" y="218.0"/>
        <omgdi:waypoint x="512.0" y="217.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowTimeout" id="BPMNEdge_flowTimeout">
        <omgdi:waypoint x="445.0" y="263.0"/>
        <omgdi:waypoint x="445.0" y="310.0"/>
        <omgdi:waypoint x="480.0" y="310.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowAfterAutoApprove" id="BPMNEdge_flowAfterAutoApprove">
        <omgdi:waypoint x="530.0" y="280.0"/>
        <omgdi:waypoint x="530.0" y="235.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowAfterWait" id="BPMNEdge_flowAfterWait">
        <omgdi:waypoint x="548.0" y="217.0"/>
        <omgdi:waypoint x="600.0" y="217.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowFinal" id="BPMNEdge_flowFinal">
        <omgdi:waypoint x="700.0" y="217.0"/>
        <omgdi:waypoint x="740.0" y="217.0"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值