前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >利用规则引擎搭建任务编排引擎

利用规则引擎搭建任务编排引擎

作者头像
用户3147702
发布于 2022-06-27 08:49:52
发布于 2022-06-27 08:49:52
2.3K00
代码可运行
举报
运行总次数:0
代码可运行

1. 引言

上一篇文章中,我们介绍了规则引擎的基本算法与使用:

规则引擎从入门到实践

我们看到,规则引擎的基础算法 Rete 算法其实是基于有向无环图的一种算法。

事实上,在实际工作生活中,并不是只有我们的逻辑推理是由有向无环图构成的,复杂的任务编排执行也可以被改造为有向无环图的形式。

2. 示例 -- 文章发布

下面来举个例子,我们需要构建一个博客文章发布系统,用户在这个博客系统中发布文章的流程很简单:

  1. 首先,对文章进行预处理,抽取文章关键字;
  2. 第 1 步完成后,将文章推送给机器学习算法模型自动审核与人工审核;
  3. 如果机器学习算法模型审核通过,按照机器学习算法计算结果,更新文章内容;
  4. 如果人工审核通过,则将文章状态更改为已发布,执行发布流程。

进一步,机器学习算法可能对文章内容进行自动修改,而人工审核可能对博客投稿的频道进行修改,虽然最终是否执行发布流程依赖于人工审核结果,但由于机器学习审核与人工审核是并发进行的,所以 3、4 两步存在竞争条件,需要复杂的加锁、判断逻辑。

我们看到,仅仅是上述四个步骤,就已经让我们的业务代码中出现了难以维护的加锁、判断逻辑,如果接下来又有新的需求:

当发布流程执行完成后,需要将机器学习算法模型计算结果推送给 C 部门。

那么,我们需要在上述流程中补充以下逻辑:

  1. 步骤 3 需要判断是否已经完成人工审核,如果是,则执行推送计算结果给 C 部门操作;如果否,则执行放置缓存操作;
  2. 步骤 4 需要判断缓存中是否已经存在算法计算结果,如果是,则在执行发布流程后执行推送操作。

这个简单的需求,我们来画一个泳道图:

图中用虚线框住的部分存在竞争条件,可见,整个流程变得极为复杂,日常维护、问题排查、后续改进等等都难以进行。

那么,针对这样的复杂场景,有什么办法可以优化吗?

3. 用规则引擎简化流程

3.1 问题复杂的原因

为什么一个看似简单的文章发布系统的例子实现起来却是如此复杂呢?

原因在于我们划分整个流程各步骤的粒度过粗,导致新的逻辑加入时难以应对。

同时,并发场景下,对于竞争条件的保护代码与业务代码耦合,造成了业务代码难以维护的问题。

只要有一个流程编排引擎,让他去处理流程各节点之间的依赖问题,就可以让我们仅仅将目光集中于业务,而不用去为缓存、加锁、判断等逻辑操心了。

3.2 文章发布流程图形化

首先,我们需要绘制出上述文章发布流程中各个任务节点构成的有向无环图:

经过流程编排,我们让后一个节点严格依赖前一个节点,将上述场景的泳道图改造为上述的有向无环图,整个文章发布流程是不是就十分简化了呢?

3.3 代码编写

3.3.1 状态记录

首先,我们需要一个类实例,实现整个编排引擎执行过程中各节点状态的记录:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 package cn.techlog.testjava.main.drools.article_publish;
 
 import java.util.Map;
 
 public class PublishProcess {
     private Integer preProcess;
     private Integer pushMonitor;
     private Integer receiveManualMonitor;
     private Integer receiveMachineMonitor;
     private Integer processManualMonitor;
     private Integer processMachineMonitor;
     private Map<String, String> machineMonitorResult;
 
     public Integer getPreProcess() {
         return preProcess;
     }
 
     public void setPreProcess(Integer preProcess) {
         this.preProcess = preProcess;
     }
 
     public Integer getPushMonitor() {
         return pushMonitor;
     }
 
     public void setPushMonitor(Integer pushMonitor) {
         this.pushMonitor = pushMonitor;
     }
 
     public Integer getReceiveManualMonitor() {
         return receiveManualMonitor;
     }
 
     public void setReceiveManualMonitor(Integer receiveManualMonitor) {
         this.receiveManualMonitor = receiveManualMonitor;
     }
 
     public Integer getReceiveMachineMonitor() {
         return receiveMachineMonitor;
     }
 
     public void setReceiveMachineMonitor(Integer receiveMachineMonitor) {
         this.receiveMachineMonitor = receiveMachineMonitor;
     }
 
     public Integer getProcessManualMonitor() {
         return processManualMonitor;
     }
 
     public void setProcessManualMonitor(Integer processManualMonitor) {
         this.processManualMonitor = processManualMonitor;
     }
 
     public Integer getProcessMachineMonitor() {
         return processMachineMonitor;
     }
 
     public void setProcessMachineMonitor(Integer processMachineMonitor) {
         this.processMachineMonitor = processMachineMonitor;
     }
 
     public Map<String, String> getMachineMonitorResult() {
         return machineMonitorResult;
     }
 
     public void setMachineMonitorResult(Map<String, String> machineMonitorResult) {
         this.machineMonitorResult = machineMonitorResult;
     }
 }

3.3.2 编写规则引擎文件 drl

根据流程编排的有向无环图,就可以完成 drl 文件的编写了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 package cn.techlog.testjava.main.drools.test
 import cn.techlog.testjava.main.drools.article_publish.PublishProcess
 import java.util.Map
 import java.util.HashMap
 
 rule "pre_process"
     when
         $publishProcess: PublishProcess(preProcess == null || preProcess == 0)
     then
         System.out.println("do pre process");
         $publishProcess.setPreProcess(1);
         update($publishProcess)
     end
 
 rule "push_monitor"
     when
         $publishProcess: PublishProcess(preProcess == 1, (pushMonitor == null || pushMonitor == 0))
     then
         System.out.println("do push monitor: push manual monitor and push machine monitor");
         $publishProcess.setPushMonitor(1);
         update($publishProcess)
     end
 
 rule "process_manual_monitor"
     when
         $publishProcess: PublishProcess(receiveManualMonitor == 1, (processManualMonitor == null || processManualMonitor == 0))
     then
         System.out.println("do process manual monitor, update article category and do article publish");
         $publishProcess.setProcessManualMonitor(1);
         update($publishProcess)
     end
 
 rule "process_machine_monitor"
     when
         $publishProcess: PublishProcess(receiveMachineMonitor == 1, processManualMonitor == 1, (processMachineMonitor == null || processMachineMonitor == 0))
     then
         System.out.println("do process machine monitor, update article content and push to C department: " + $publishProcess.getMachineMonitorResult());
         $publishProcess.setProcessMachineMonitor(1);
         update($publishProcess)
     end

3.3.3 编写执行函数

接下来我们来编写程序模拟这一流程的执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 package cn.techlog.testjava.main.drools.article_publish;
 
 import cn.techlog.testjava.main.util.FileUtil;
 import org.kie.api.io.ResourceType;
 import org.kie.api.runtime.StatelessKieSession;
 import org.kie.internal.conf.MultithreadEvaluationOption;
 import org.kie.internal.utils.KieHelper;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.FutureTask;
 
 public class ArticlePublishTest {
     private static final PublishProcess publishProcess = new PublishProcess();
     private static final StatelessKieSession kieSession;
 
     static {
         String drlStr = FileUtil.getFileString("drl/article_publish.drl");
         KieHelper helper = new KieHelper();
         helper.addContent(drlStr, ResourceType.DRL);
         kieSession = helper.build(MultithreadEvaluationOption.YES).newStatelessKieSession();
     }
 
     public static void main(String[] args) {
         FutureTask<String> futureTask1 = new FutureTask<>(ArticlePublishTest::doDrl);
         FutureTask<String> futureTask2 = new FutureTask<>(ArticlePublishTest::startNode);
         Thread thread1 = new Thread(futureTask1);
         Thread thread2 = new Thread(futureTask2);
         thread1.start();
         thread2.start();
     }
 
     private static String startNode() throws InterruptedException {
         Thread.sleep(3000);
         System.out.println("-> receive machine monitor result");
         Map<String, String> result = new HashMap<>();
         result.put("result", "hello world");
         publishProcess.setMachineMonitorResult(result);
         publishProcess.setReceiveMachineMonitor(1);
         kieSession.execute(publishProcess);
 
         Thread.sleep(3000);
         System.out.println("-> receive manual monitor result");
         publishProcess.setReceiveManualMonitor(1);
         kieSession.execute(publishProcess);
         return null;
     }
 
     private static String doDrl() {
         kieSession.execute(publishProcess);
         return null;
     }
 }

3.3.4 执行结果

执行程序,我们看到输出了结果:

do pre process do push monitor: push manual monitor and push machine monitor -> receive machine monitor result -> receive manual monitor result do process manual monitor, update article category and do article publish do process machine monitor, update article content and push to C department: {result=hello world}

虽然在我们的异步接收线程中,机器审核结果早于人工审核结果先被收到,但由于我们的流程编排,机器审核结果的处理则直到人工审核结果处理后才完成执行。

4. 说明

我们看到,在我们的模拟文章发布流程中,我们将复杂、多分支、存在竞争条件的文章发布流程通过规则引擎模拟实现的任务编排引擎成功变成了串行执行,没有竞争条件存在的简单流程。

但这个例子仍然是非常基础的,在实际的场景中,你可能还是会遇到以下这些问题:

4.1 任务重做

在实际场景中,任务的某个节点需要重做是经常让人很头疼的一件事,因为对于线上场景,任务经常是可重入的,否则重复回调等常见情况就会造成你的任务出现问题,但既然任务是可重入的,那怎么让你的任务重新执行一次呢?进行上述改造以后,就不再存在这个问题了,因为编排引擎决定了任务不会被执行两次,如果某个任务需要被重新执行,只需要将状态描述类中对应的字段置为 0,其他不需要执行的任务对应的状态字段置为 1,即可保证仅重新执行该节点,而无需担心其他节点意外受到影响了。

4.2 性能

从性能上来说,规则文件的解析与实例化是非常耗时的,因此,提前 build,例如在项目启动时就完成所有规则的实例化,然后将 kieSession 放在内存中,这样在实际执行的过程中,性能会有明显提升。另一方面,不要在单个规则中加入复杂的判断逻辑,对于复杂场景,拆分成多个 rule 可以有效提升性能,同时,不要在 then 块中进行判断,所有的判断应该都放在 when 块中。

4.3 并发执行

显然,生产环境中要比上述 demo 更加复杂,最基本的一点,线上环境中,各个任务不会都在同一台机器上执行,同时,接收到异步回调的节点也会分布在不同的服务器上,虽然通过流程编排,解决了业务代码中的竞争条件,极大地简化了整个流程,但任务的状态描述结构仍然需要在分布式环境中共享,这就需要一个中心化的缓存,同时,分布式环境下,对任务状态对象中字段的修改也同样存在着竞争条件,因此最好的方法是将这个状态对象的缓存与竞争条件的加锁逻辑封装为一个新的工程框架,这就是一个任务编排引擎。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
规则引擎从入门到实践
小明是一个兢兢业业的服务端程序员,有一天产品经理找到他说,我们要给用户发一条消息,消息的内容按照用户的积分分为三档,1000 以下的用户发:
用户3147702
2022/06/27
1.4K0
规则引擎从入门到实践
Drools - 规则引擎快速体验
Drools 是用 Java 语言编写的开放源码规则引擎,使用 Rete 算法(参阅 参考资料)对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人 Hello World pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</gro
十毛
2019/03/27
1.7K0
SpringBoot2 整合 Drools规则引擎,实现高效的业务规则
B、规则流程:如果paramId不为null,参数标识是+号,执行添加规则,-号,执行移除规则操作。
知了一笑
2019/10/09
1.4K0
SpringBoot2 整合 Drools规则引擎,实现高效的业务规则
【Drools】值得打工人学习的规则引擎Drools<一>
规则引擎:全称为业务规则管理系统,英文名为BRMS(即Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。 需要注意的是规则引擎并不是一个具体的技术框架,而是指的一类系统,即业务规则管理系统。 目前市面上具体的规则引擎产品有:drools、VisualRules、iLog等。 规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出平台。
沁溪源
2020/11/13
8.4K0
【Drools】值得打工人学习的规则引擎Drools<一>
JAVA规则引擎工具有哪些?
Drools 是一个强大的业务规则管理系统(BRMS),它提供了一整套用于定义、管理和执行业务规则的工具。
科技新语
2024/07/28
2490
JAVA规则引擎工具有哪些?
Drools规则引擎入门指南(一)
Drools的规则文件是以*.drl结尾的文件,我们来看一个最简单的规则文件中都是包含什么。
Java学习录
2019/04/18
1.6K0
《Drools7.0.0.Final规则引擎教程》第3章 3.2 KIE概念&FACT对象
本文介绍了Drools规则引擎的基本概念、使用场景、规则语法、Fact对象以及FactHandler对象在规则执行过程中的作用,并给出了相关示例。
程序新视界
2018/01/08
1.2K0
《Drools7.0.0.Final规则引擎教程》第3章 3.2 KIE概念&FACT对象
规则引擎Drools在贷后催收业务中的应用
在日常业务开发工作中我们经常会遇到一些根据业务规则做决策的场景。为了让开发人员从大量的规则代码的开发维护中释放出来,把规则的维护和生成交由业务人员,为了达到这种目的通常我们会使用规则引擎来帮助我们实现。
2020labs小助手
2022/11/29
1.6K0
规则引擎之drools入门
现实生活中,规则无处不在。对于某些企业级应用,诸如欺诈检测软件,购物车,活动监视器,信用和保密应用之类的系统,经常会有大量的、错综复杂的业务规则配置,而且随着企业管理者的决策变化,这些业务规则也会随之发生更改。我们开发人员不得不一直处理软件中的各种复杂问题,不仅需要将所有数据进行关联,还要尽可能快地一次性处理更多的数据,甚至还需要以快速的方式更新相关机制。
lyb-geek
2018/07/26
5.6K0
规则引擎之drools入门
小明历险记:规则引擎Drools教程一
小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看。 小明的烦恼 活动规则是根据用户购买订单的金额给用户送相应的积分,购买的越多送的积分越多,用户可以使用积分来兑换相应的商品,我们这次活动的力度很大,肯定会吸引很多的用户参加,产品经理小王兴高采烈唾液横飞的对小明讲到。小明心想,又tm来这套,这次需求又要变更多少次呢?表面上还的配合,说赶紧把规则给我们吧,早点开发早点上线,小王说这次需求老简单啦,估计你们两
纯洁的微笑
2018/07/20
1.2K0
Spring Boot + 规则引擎Drools,强!
现在有这么个需求,网上购物,需要根据不同的规则计算商品折扣,比如VIP客户增加5%的折扣,购买金额超过1000元的增加10%的折扣等,而且这些规则可能随时发生变化,甚至增加新的规则。面对这个需求,你该怎么实现呢?难道是计算规则一变,就要修改业务代码,重新测试,上线吗。
码猿技术专栏
2023/05/01
2.4K0
Spring Boot + 规则引擎Drools,强!
Java各种规则引擎
(2)新建配置文件/src/resources/META-INF/kmodule.xml
matinal
2020/11/27
5.2K1
Java各种规则引擎
Drools规则引擎-memberOf操作
规则引擎技术讨论2群(715840230)有同学提出疑问,memberOf的使用过程中如果,memberOf之后的参数不是集合也不是数组,而是格式如“1,2,3,4”的字符串,那么Drools是否会讲其转换成数组?
程序新视界
2019/08/01
1.2K0
规则引擎深度对比,LiteFlow vs Drools!
Drools是一款老牌的java规则引擎框架,早在十几年前,我刚工作的时候,曾在一家第三方支付企业工作。在核心的支付路由层面我记得就是用Drools来做的。
码猿技术专栏
2023/05/01
8.4K0
规则引擎深度对比,LiteFlow vs Drools!
规则引擎 - drools 使用讲解(简单版) - Java
drools是一款标准、效率高、速度快的开源规则引擎,基于ReteOO算法,目前主要应用场景在广告、活动下发等领域非常多,比如APP的活动下发,通常都是有很多条件限制的,且各种活动层出不穷,无法代码穷举,而如果每次为了一个活动重新发版上线,显然是不合理的,因此通过drools将活动中变的部分抽象为一个个单独的规则文件,来屏蔽这部分的变化,使得系统不需要从代码层面做出改变,当然了为了更加极致的抽象,通常还需要对规则中的一些可配条件(大于、小于、等于、范围、次数等)也提取到数据库中,这样在现有规则不满足要求时,可以直接通过更改数据库的对应规则表来完善,同样不需要改代码;
HoLoong
2020/09/21
2K0
《Drools7.0.0.Final规则引擎教程》第3章 3.1 Hello World 实例
本文介绍了如何使用Drools规则引擎实现业务逻辑,通过一个具体的实例对Drools规则进行了介绍,包括规则定义、编译、解释执行和规则优化等步骤。同时,还介绍了Drools的配置文件kmodule.xml的用法。
程序新视界
2018/01/08
1.7K0
《Drools7.0.0.Final规则引擎教程》第3章 3.1 Hello World 实例
《Drools7.0.0.Final规则引擎教程》第3章 3.2 KIE API解析
本文介绍了Drools规则引擎的基本概念、核心组件、基本用法和高级用法,包括KieSession、KieBase、KieRepository等,并介绍了基于Maven的规则引擎配置示例。
程序新视界
2018/01/08
2K0
《Drools7.0.0.Final规则引擎教程》第3章 3.2 KIE API解析
《Drools7.0.0.Final规则引擎教程》Springboot+规则重新加载
该文介绍了一种基于SpringBoot和Drools的规则引擎,用于规则校验,并提供了相关代码实现。具体实现包括:定义规则文件、使用构建工具编译规则文件、定义校验逻辑、使用SpringBoot加载规则文件、定义规则校验接口、基于Drools规则引擎实现规则校验。实现了代码的自动生成和规则校验,具有较好的实用价值。
程序新视界
2017/12/29
2.9K0
《Drools7.0.0.Final规则引擎教程》Springboot+规则重新加载
drools规则动态化实践
业务逻辑中经常会有一些冗长的判断,需要写特别多的if else,或者一些判断逻辑需要经常修改。这部分逻辑如果以java代码来实现,会面临代码规模控制不住,经常需要修改逻辑上线等多个弊端。这时候我们就需要集成规则引擎对这些判断进行线上化的管理
用户6256742
2024/06/01
6180
drools规则动态化实践
SpringBoot入门建站全系列(三十四)使用Drools规则引擎做排班系统
Drools 是用 Java 语言编写的开放源码规则引擎,使用 Rete 算法对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。
品茗IT
2020/05/28
2.6K0
推荐阅读
相关推荐
规则引擎从入门到实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档