Activity-定义边界事件

流程流转到一个普通任务时, 如果在指定时间内没有完成, 就会触发定时边界事件。

流程xml如下

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL
             http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd">

  <process id="boundaryEventFlow" name="定时边界事件">
    <startEvent id="startEvent"/>
    <userTask id="commonTask" name="Common Task"/>
    <!-- 声明边界事件, attachedToRef 指定边界事件的起源 -->
    <boundaryEvent id="boundaryEvent" name="Timer" attachedToRef="commonTask" cancelActivity="true">
      <timerEventDefinition>
        <!-- 在任务开始 5 秒之后触发, 如果commonTask中的任务还没有完成,就会触发边界事件,把流程走向Timeout Task -->
        <timeDuration>PT5S</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <userTask id="timeoutTask" name="Timeout Task"/>
    <endEvent id="end1"/>
    <endEvent id="end2"/>
    <sequenceFlow sourceRef="startEvent" targetRef="commonTask"/>
    <sequenceFlow sourceRef="commonTask" targetRef="end1"/>
    <sequenceFlow sourceRef="boundaryEvent" targetRef="timeoutTask"/>
    <sequenceFlow sourceRef="timeoutTask" targetRef="end2"/>
  </process>

</definitions>

一个流程触发,走到了Common  Task,如果这个Common Task在5秒内没有完成走到end1,那么,就会触发事件边界事件,走到Timeout Task。代码示例:

package common;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.FileUtils;

public class ProcessEngineUtil {
    public ProcessEngineConfiguration configuration;

    public ProcessEngine processEngine;

    public RepositoryService repositoryService;

    public ProcessDefinition processDefinition;

    public ProcessEngineUtil(String bpmnFile) {
        configuration =
            ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        processEngine = configuration.buildProcessEngine();


        processEngine.getProcessEngineConfiguration().getAsyncExecutor().start();

        repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
            .addClasspathResource(bpmnFile)
            .deploy();

        String deploymentId = deployment.getId();
        processDefinition = repositoryService.
            createProcessDefinitionQuery().
            deploymentId(deploymentId)
            .singleResult();
    }

    public ProcessDefinition getProcessDefinition() {
        return processDefinition;
    }

    public ProcessEngine getProcessEngine() {
        return processEngine;
    }

    public void draw(ProcessInstance processInstance){
        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator(); // 创建默认的流程图生成器
        String imageType = "png"; // 生成图片的类型
        List<String> highLightedActivities = new ArrayList<>(); // 高亮节点集合
        List<String> highLightedFlows = new ArrayList<>(); // 高亮连线集合
        List<HistoricActivityInstance> hisActInsList = processEngine.getHistoryService().createHistoricActivityInstanceQuery()
            .processInstanceId(processInstance.getProcessInstanceId())
            .list(); // 查询所有历史节点信息
        hisActInsList.forEach(historicActivityInstance -> { // 遍历
            if("sequenceFlow".equals(historicActivityInstance.getActivityType())) {
                // 添加高亮连线
                highLightedFlows.add(historicActivityInstance.getActivityId());
            } else {
                // 添加高亮节点
                highLightedActivities.add(historicActivityInstance.getActivityId());
            }
        });
        String activityFontName = "宋体"; // 节点字体
        String labelFontName = "微软雅黑"; // 连线标签字体
        String annotationFontName = "宋体"; // 连线标签字体
        ClassLoader customClassLoader = null; // 类加载器
        double scaleFactor = 1.0d; // 比例因子,默认即可
        boolean drawSequenceFlowNameWithNoLabelDI = true; // 不设置连线标签不会画


        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        BpmnAutoLayout bpmnAutoLayout = new BpmnAutoLayout(bpmnModel);
        bpmnAutoLayout.setTaskHeight(120);
        bpmnAutoLayout.setTaskWidth(120);
        bpmnAutoLayout.execute();
        InputStream
            inputStream = defaultProcessDiagramGenerator.generateDiagram(bpmnModel, imageType, highLightedActivities
            , highLightedFlows, activityFontName, labelFontName, annotationFontName, customClassLoader,
            scaleFactor);  // 获取输入流
        try {
            // 先将图片保存
            FileUtils.copyInputStreamToFile(inputStream, new File("1.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package com.lala.timerboundary;

import com.lala.hexo.DemoMain;
import common.ProcessEngineUtil;
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TimerBoundary {
    public static void main(String[] args)
        throws InterruptedException {
        ProcessEngineUtil processEngineUtil = new ProcessEngineUtil("boundaryEvent.bpmn20.xml");
        ProcessEngine processEngine = processEngineUtil.getProcessEngine();
        ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey("boundaryEventFlow");
        // task 列表
        List<Task> beforeSleepTaskList = processEngine.getTaskService().createTaskQuery().list();
        for (Task task : beforeSleepTaskList) {
            System.out.println("休眠前 task.name = " + task.getName());
            // processEngine.getTaskService().complete(task.getId());
        }
        // 强制睡眠等待边界事件触发
        Thread.sleep(10 * 1000);
        // task 列表
        List<Task> afterSleepTaskList = processEngine.getTaskService().createTaskQuery().list();
        System.out.println("休眠后 task 总数:  " +  afterSleepTaskList.size());
        for (Task task : afterSleepTaskList) {
            System.out.println("休眠后 task.name = " +  task.getName());
        }
        processEngineUtil.draw(processInstance);
    }
}

以上输出:

流程图如下:

ps。如果发现定时器失效,可能是没有加

processEngine.getProcessEngineConfiguration().getAsyncExecutor().start(); // 开启定时器

实例一:

如果把main函数中注释

processEngine.getTaskService().complete(task.getId()); 

那么,流程就不会走到Timeout Task中,输入会变成:

流程如下:

实例二:

如果代码改成:在休眠之后,再去触发完成common Task的事件

        List<Task> beforeSleepTaskList = processEngine.getTaskService().createTaskQuery().list();
        // 强制睡眠等待边界事件触发
        Thread.sleep(10 * 1000);
        for (Task task : beforeSleepTaskList) {
            System.out.println("休眠后 task.name = " + task.getName());
            processEngine.getTaskService().complete(task.getId());
        }

就会抛出处理异常,以为这时流程已经走到了timeout Task了。

<think>好的,我现在需要处理用户关于Activiti7定时事件实现方式和错误处理的问题。首先,我得回忆一下Activiti7的相关知识。Activiti是一个工作流引擎,定时事件在流程中用于触发特定时间点或间隔的任务。用户提到了定时事件的实现方式和错误处理,可能需要详细说明配置方法和异常处理机制。 首先,关于定时事件的实现方式。Activiti7支持定时器开始事件、中间定时器和边界定时器等类型。定时器开始事件用于在指定时间启动流程,中间定时器用于等待一段时间后继续流程,边界定时器则是在某个任务上设置超时。这些都需要在BPMN流程定义中配置,比如使用timeDate、timeDuration或timeCycle属性。例如,timeCycle可以用Cron表达式来定义重复执行的时间规则。 然后,错误处理方面,用户可能想知道当定时事件出现错误时如何处理。Activiti7中的错误结束事件和错误边界事件是关键。错误结束事件会终止当前流程实例,并标记为错误状态,而错误边界事件可以捕获特定的错误并执行补偿逻辑。例如,在边界事件中配置错误代码,当子流程抛出错误时,主流程可以捕获并处理,比如发送通知或回滚操作。 接下来,我需要参考用户提供的引用内容。引用[2]提到了Activiti6.0的定时器开始事件和错误开始事件,但用户问的是Activiti7,不过基本概念可能相似。引用[3]和[4]涉及使用delay和定时任务的具体代码实现,但Activiti7的定时事件更多是流程定义层面的配置,而非代码中的定时器。不过,可能需要结合代码示例,比如在服务任务中调用定时服务。 需要注意的是,用户的问题可能还涉及如何在流程中处理定时事件引发的错误,比如超时后的补偿措施。这时候需要结合错误边界事件和补偿中间件,或者使用服务任务执行异常处理逻辑。同时,定时事件配置的正确性也很重要,比如Cron表达式是否正确,否则可能导致流程无法按预期触发。 最后,生成相关问题时要覆盖实现方式、错误处理、配置注意事项、与旧版本差异以及调试方法等方面,帮助用户全面理解。确保回答结构清晰,分点说明,并正确使用LaTeX格式,如流程变量使用$variable$,独立公式用$$...$$,但这里可能较少涉及数学公式,更多是流程配置和代码示例。</think>### Activity7 定时事件实现方式与错误处理 #### 一、定时事件实现方式 1. **定时器开始事件** 在BPMN流程定义中,通过`timerEventDefinition`配置定时触发条件,支持以下属性: - `timeDate`:指定具体时间点(ISO 8601格式),例如: ```xml <startEvent id="timerStart"> <timerEventDefinition> <timeDate>2024-01-01T00:00:00Z</timeDate> </timerEventDefinition> </startEvent> ``` - `timeDuration`:延迟触发时间,例如`PT5M`表示延迟5分钟。 - `timeCycle`:周期性触发(Cron表达式或重复间隔),例如`0 0/30 * * * ?`每半小时执行一次[^2]。 2. **中间定时事件** 用于在流程执行中暂停并等待特定时间,常用于超时控制: ```xml <intermediateCatchEvent id="timerCatch"> <timerEventDefinition> <timeDuration>PT1H</timeDuration> </timerEventDefinition> </intermediateCatchEvent> ``` 3. **边界定时事件** 附加到任务或子流程上,实现超时中断: ```xml <boundaryEvent id="timeoutBoundary" attachedToRef="task1"> <timerEventDefinition> <timeDuration>PT30M</timeDuration> </timerEventDefinition> </boundaryEvent> ``` #### 二、错误处理机制 1. **错误结束事件** 当流程因错误终止时,通过`errorEndEvent`标记错误类型,例如: ```xml <endEvent id="errorEnd"> <errorEventDefinition errorRef="paymentTimeoutError"/> </endEvent> ``` 流程实例状态将变为`ERROR`,需通过API查询处理[^1]。 2. **错误边界事件** 捕获子流程或任务抛出的错误,执行补偿逻辑: ```xml <boundaryEvent id="errorHandler" attachedToRef="subProcess"> <errorEventDefinition errorRef="networkError"/> </boundaryEvent> <sequenceFlow sourceRef="errorHandler" targetRef="retryTask"/> ``` 3. **定时事件错误场景处理** - **Cron表达式错误**:部署流程时校验失败,需修正表达式格式。 - **执行超时**:通过边界定时事件触发重试或通知: ```xml <serviceTask id="retryTask" activiti:class="com.example.RetryService"/> ``` #### 三、代码集成示例 通过服务任务调用定时逻辑(结合Quartz或Spring Scheduler): ```java public class TimerJobHandler implements JavaDelegate { @Override public void execute(DelegateExecution execution) { // 调用定时任务逻辑,例如: ScheduleService.scheduleRetry(execution.getVariables()); } } ``` 需确保定时任务与流程引擎的事务一致性[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值