余鸿伟 發表於 2025-6-26 11:14:00

三方系统集成(低代码)平台实践

<blockquote data-pm-slice="0 0 []">
<p>作者:vivo IT 平台团队- Wang Qin</p>
<p>本文从作者实际痛点出发,到产生愿景,最后再到落地的全过程,并结合实例案例,介绍了一些核心设计思路,希望读者阅读后对vivo分销业务,能有一些了解,也希望能对读者在应用的认证鉴权、流程编排、低代码等方面有所启发。</p>
</blockquote>
<h1>一、背景和痛点</h1>
<p>本文首先对vivo分销业务系统(简称V-Work,V-Work是分销系统的Portal,非1个系统)做个简单的介绍,V-Work作为vivo手机/智能终端等全系产品的分销系统,覆盖了全球范围线上/线下的供应和销售网。</p>
<p><strong>线下业务:</strong>主要支撑各省市代理,以及下属零售商,零售商下的门店,门店到消费者的货物流和财务流,这些业务的操作入口一般直接在V-Work页面发起。</p>
<p><strong>线上业务:</strong>核心是通过对接各类B2C平台、O2O平台、政企平台、运营商系统等,将订单同步到V-Work进行履约,通过调度自有WMS、三方WMS、三方TMS进行仓库作业和物流发货,同时返回发货的信息给到各类下单系统。</p>
<p><strong>全球部署:</strong>V-Work共部署了4套集群(分别是国内机房、海外1机房、海外2机房、海外3机房),服务于全球用户。</p>
<p>类似很多互联网公司系统的迭代,V-Work系统经历过的架构演进:</p>
<p><strong>单体架构:</strong>&nbsp;2022年前V-Work是有多个包括订单、履约、库存、策略模块的独立单体系统。</p>
<p><strong>微服务架构:</strong>&nbsp;2022年开始进行了系统架构升级,将通用模块进行了抽取,形成了独立的服务,避免了重复造轮子的问题,目前整个架构升级工作还在持续进行中。</p>
<img src="https://static001.geekbang.org/infoq/74/74284e9f38d84b57ec6dde1c1d955271.gif">
<p>随着V-Work承接的业务场景越来越多(订单业务从线下分销拓展到线上电商平台+运营商平台等,仓储物流从vivo内部的代理wms拓展为支撑各个区域的承运仓),导致对接的三方系统也呈现陡增之势,在系统迭代过程期间,主要遇到了以下几个问题:</p>
<ol>
<li>
<p data-number="1">V-Work履约流程相对是固定的,但每对接一个三方平台时,都要开发一套适配代码, 这种硬编码的方式效率不高。</p>
</li>
<li>
<p data-number="2">从代码提交到可用时间慢,特别在联调和测试环节,因需转换的内容繁琐,转换的字段较多,很容易出现错误,这个时候要经过代码调整、提交,DEVOPS流水线,应用启动,才最终可用,而不能即时生效。</p>
</li>
<li>
<p data-number="3">三方集成的代码,对开发能力本身的要求不高,但因为是硬编码,所以还是需要开发人员,投入产出比不高。</p>
</li>
<li>
<p data-number="4">不同三方系统,因会抽象出一些公共代码,这个时候就有可能出现比如改了抖音对接的公共代码,影响了其它平台。</p>
</li>
<li>
<p data-number="5">每次对接一个平台,都要开发一套针对该平台的授权代码,定制开发导致效率低。</p>
</li>
<li>
<p data-number="6">日志运维功能定制化,因每个平台的接口字段不同,导致日志的记录和展示等运维功能都是定制开发,成本较高。</p>
</li>
</ol>
<p>透过问题的表面看本质,在有了多个三方平台集成的前车之鉴后,我开始反思能否针对当前的各种能力可以进行总结和抽象,最终形成一套配置化平台,即产生了一开始的三方系统集成平台,当初只是想解决vivo内部系统和vivo外部系统的集成,让内部业务系统开发人员仅需专注自身业务的开发,而不care外部的接口定义,能提升研发效率,来快速支撑业务的交付。</p>
<p>当三方集成平台成功上线,并经过2个月的推广后,很快发现他的应用场景不止能支持内外部系统的集成,内部系统之间的集成也很适合,比如结算中心和ERP的对接,2个系统都具有各自的业务模型,结算需要把过账数据推给ERP系统进行财务结算,就涉及到数据的转换和适配,本平台也是较好的应用场景。</p>
<p>所以最终将本平台命名为通用集成平台(Common Integration Platform),简称CIP,给他的定位是:<strong>适合多个核心业务系统直接进行对接,业务系统只需关注自身业务,通过本平台进行适配和桥接,可作为当前的适配系统、前置系统、业务网关系统,甚至渠道系统的配置化替代解决方案。</strong></p>
<p>&nbsp;</p>
<h1>二、整体架构</h1>
<h2>2.1 架构目标</h2>
<p><strong>1.100%配置化(低代码)</strong></p>
<p>要完成一次有实际意义的系统间的集成,肯定不止会有源系统和目标系统参与,期间还会涉及其它系统的参与,即会存在多个系统的多个接口协同完成一次业务流程,那就需要有编排和串联系统和接口的能力,这种能力采用配置化的解决方案进行落地,力争达到低代码化。</p>
<p>配置数据的存储上,常见的有XML和JSON两种格式,考虑到使用习惯和灵活性,最终选择了JSON作为配置元数据的存储格式。</p>
<p>站在平台建设角度,要做到这一点,最考验的是过往经验,以及对经验的归纳总结,然后抽象的能力,同时要有对可能变化点的识别能力,即对不确定的方面,要留好扩展性,这样才能建设一个健康稳定发展的平台。</p>
<p><strong>2. 自助式接入</strong></p>
<p>这里自助式有2个层面的含义:</p>
<p><strong>第一层:</strong>指的是可以由业务团队自行配置和调试,而不限于必须是CIP平台的人员,比如V-Work也会对接多个三方仓储系统,去提高我们的履约时效,就会涉及V-Work和顺丰WMS、京东宙斯、EMS CTL的对接,那完全可以由V-Work中履约模块的人员在本平台完成配置和调试。</p>
<p><strong>第二层:</strong>配置化+可视化可以降低使用者的门槛,类似一名HR在OA系统给员工办理入职那样简单,只要简单培训,即可上手,目标是运维、产品、测试、甚至业务都可以轻松在本平台上进行操作,完成业务实施。</p>
<p><strong>3. 开发效率提升</strong></p>
<p>通过对相似的事物进行抽象,抽象成各个具有独自特性的积木,同时将变化的东西看作是数据,而非代码本身,可灵活支撑各业务的个性化需求,提高开发效率,降低人力成本。</p>
<p><strong>4. 隔离性</strong></p>
<p><strong>物理隔离:</strong>通过部署多套集群,可以让项目之间做到物理隔离,比如“抖音对接项目”不会影响“顺丰WMS对接项目”(可以见后文的部署架构)。</p>
<p><strong>逻辑隔离:</strong>不像传统的硬编码方式,因系统对接之间会复用某些代码,导致相互影响,本平台配置管理上天然就具有隔离性,通过项目和项目之间,项目下的流程之间,都是可独立配置,不会影响到其它项目和任务流,实现了逻辑上的隔离,即真正做到了不同的需求的应用之间集成,不会相互影响。</p>
<p><strong>5. 配置即时生效</strong></p>
<p>配置完能立即生效,而不需要经过代码提交,分支合并,持续交付流水线,应用启动的等待时间,也不会因为发布应用导致的服务不可用(现在V-Work做不到完全无损部署)。</p>
<p>&nbsp;</p>
<h2>2.2 系统架构</h2>
<img src="https://static001.geekbang.org/infoq/8a/8a8479d4ae0f971eb0f6d582bd08bc62.gif">
<p><strong>核心概念解释:应用、触发器、执行器、连接器、项目、任务流:</strong></p>
<p>(1)“应用、触发器、执行器、连接器”:属于静态配置,只需配置一次,就可以在多个“任务流”中被引用。</p>
<ul>
<li>
<p><strong>应用:</strong>和我们的微服务是一一对应的,一个微服务维护成一个应用。</p>
</li>
<li>
<p><strong>触发器:</strong>流程中的首节点,流程中的触发节点,一个任务流只能含有一个触发器。</p>
</li>
<li>
<p><strong>执行器:</strong>流程中的非首个节点,即首节点后面的所有节点都属于执行器,一个任务流可以包括多个执行器。</p>
</li>
<li>
<p><strong>连接器:</strong>是一种特殊的触发器或执行器,正常触发器和执行器通过配置完成,而连接器是需要预先进行定制开发。</p>
</li>
</ul>
<p>&nbsp;(2)“项目、任务流”:属于动态配置,每一次项目的实施都是不同的配置。</p>
<ul>
<li>
<p><strong>项目:</strong>用于组织完成一次需求的实施,可包括多个任务流。</p>
</li>
<li>
<p><strong>任务流:</strong>用于串联触发器、连接器和执行器且带有方向的一条流程任务。</p>
</li>
</ul>
<img src="https://static001.geekbang.org/infoq/7c/7c4ae69ed30f8265bff8ccc64fa38247.gif">
<p>三方系统集成场景,包括三层架构:</p>
<ul>
<li>
<p><strong>上层是外部三方系统</strong>,目前V-Work对接的三方系统主要包括:国内和海外的主流电商平台、O2O平台、三大运营商系统,以及V-Work线下代理公司系统的集成。</p>
</li>
<li>
<p><strong>中层由开放平台和CIP平台组成</strong>:开放平台主要对外提供了网关功能,包括统一的鉴权和限流方案。</p>
</li>
<li>
<p><strong>底层</strong>是V-Work内的多个系统组成。</p>
</li>
</ul>
<img src="https://static001.geekbang.org/infoq/83/836ebda5314b708e42150ad44fe10560.png">
<p>部署架构重点支持了不同项目的物理隔离,当前CIP部署架构:</p>
<ul>
<li>
<p><strong>CIP-CORE:</strong>主集群(包括电商、政企、代理赋能等业务)。</p>
</li>
<li>
<p><strong>CIP-CPC:</strong>工厂业务集群(包括vivo的制造和供应域的各类系统)。</p>
</li>
<li>
<p><strong>CIP-WMS:</strong>仓储和物流业务集群(包括各类WMS和TMS系统)。</p>
</li>
<li>
<p><strong>CIP-Finance:</strong>财务业务集群(ERP和三方财务系统)。</p>
</li>
<li>
<p><strong>CIP-ADMIN:</strong>服务于以上CIP-CORE、CIP-CPC等的控制台,处理非核心功能,与核心功能分离。</p>
</li>
</ul>
<p>&nbsp;</p>
<h1>三、关键设计</h1>
<h2>3.1 内置常见接口授权方法</h2>
<img src="https://static001.geekbang.org/infoq/6e/6e8993121f3afada6a11bc33114d594d.jpeg">
<p>以下用最常见的2种授权方式(hmac和oAuth2)举例说明</p>
<p><strong>(1)hmac授权</strong></p>
<p>加签方式定义:</p>
<p>语法定义:</p>
<pre><code>sign(key-values,&nbsp;start=‘’,&nbsp;end=‘’, connector=‘’, signType=‘md5/rsa’, target=‘=’, exclude=‘’,extra=json)</code></pre>
<p>&nbsp;</p>
<ul>
<li>
<p><strong>key-values:</strong>要加签的业务字段的字段名和字段值</p>
</li>
<li>
<p><strong>start:</strong>待加签串的起始额外内容</p>
</li>
<li>
<p><strong>end:</strong>待加签串的结尾额外内容</p>
</li>
<li>
<p><strong>connector:</strong>多个业务字段的连接符</p>
</li>
<li>
<p><strong>signType:</strong>加签的加密类型</p>
</li>
<li>
<p><strong>target:</strong>业务字段名和字段值的连接符</p>
</li>
<li>
<p><strong>exclude:</strong>要过滤的业务字段</p>
</li>
<li>
<p><strong>extra:</strong>扩展配置</p>
<p>① “innerFormat”=false //嵌套对象是否格式化,默认true</p>
<p>② “innerSort”=false //嵌套对象是否参与排序,默认true</p>
<p>③ “salt”=”qbc12” //hmac加盐</p>
<p>④“innerExcludeKey”=true ,“outerExcludeKey”=true //是否过滤字段key,默认false</p>
<p>⑤resultType=base64/hex //返回的数据格式</p>
</li>
</ul>
<p><strong>(2)oAuth2授权</strong></p>
<p>仅需2步就可配置一个oAuth2授权类型系统的集成。</p>
<p>第一步:接口授权配置,以下以tiktok举例:</p>
<pre><code>&nbsp;&nbsp;"create": { &nbsp;
&nbsp; &nbsp;&nbsp;"url":&nbsp;"https://auth.tiktok-shops.com/api/v2/token/get", &nbsp;
&nbsp; &nbsp;&nbsp;"param": { &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"app_key":&nbsp;"{# ad.ak #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"auth_code":&nbsp;"{# ad.code #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"app_secret":&nbsp;"{# ad.sk #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"grant_type":&nbsp;"authorized_code"
&nbsp; &nbsp; }, &nbsp;
&nbsp; &nbsp;&nbsp;"method":&nbsp;"GET", &nbsp;
&nbsp; &nbsp;&nbsp;"resultMap": { &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"token":&nbsp;"{# ob.data.access_token #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"refresh_token":&nbsp;"{# ob.data.refresh_token #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"token_invalid_date":&nbsp;"{$&nbsp;dfconvert({# ob.data.access_token_expire_in #}*1000,'yyyy-MM-dd HH:mm:ss')&nbsp;$}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"refresh_token_invalid_date":&nbsp;"{$&nbsp;dfconvert({# ob.data.refresh_token_expire_in#}*1000,'yyyy-MM-dd HH:mm:ss')&nbsp;$}"
&nbsp; &nbsp; } &nbsp;
&nbsp; }, &nbsp;
"getCode": { &nbsp;
&nbsp; &nbsp;&nbsp;"url":&nbsp;"https://services.tiktokshop.com/open/authorize", &nbsp;
&nbsp; &nbsp;&nbsp;"param": { &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"service_id":&nbsp;"{#ad.extra.serviceId#}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"redirectUri":&nbsp;"{$&nbsp;'https://xxx.vivo.xyz/app/authCode/factory-tiktok/tiktok/' + {#ad.shopId#}&nbsp;$}"
&nbsp; &nbsp; } &nbsp;
&nbsp; }, &nbsp;
"refresh": { &nbsp;
&nbsp; &nbsp;&nbsp;"url":&nbsp;"https://auth.tiktok-shops.com/api/v2/token/refresh", &nbsp;
&nbsp; &nbsp;&nbsp;"param": { &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"app_key":&nbsp;"{# ad.ak #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"app_secret":&nbsp;"{# ad.sk #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"grant_type":&nbsp;"refresh_token", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"refresh_token":&nbsp;"{# ad.refreshToken #}"
&nbsp; &nbsp; }, &nbsp;
&nbsp; &nbsp;&nbsp;"method":&nbsp;"GET", &nbsp;
&nbsp; &nbsp;&nbsp;"resultMap": { &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"token":&nbsp;"{# ob.data.access_token #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"refresh_token":&nbsp;"{# ob.data.refresh_token #}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"token_invalid_date":&nbsp;"{$&nbsp;dfconvert({# ob.data.access_token_expire_in #}*1000,'yyyy-MM-dd HH:mm:ss')&nbsp;$}", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"refresh_token_invalid_date":&nbsp;"{$&nbsp;dfconvert({# ob.data.refresh_token_expire_in#}*1000,'yyyy-MM-dd HH:mm:ss')&nbsp;$}"
&nbsp; &nbsp; } &nbsp;
&nbsp; } &nbsp;
}</code></pre>
<p>第二步:点击CIP分配的URL:https://xxx.vivo.xyz/app/auth?project=ina-vk&amp;app=douyin&amp;shopId=sfdsa3t8fds,会跳转到tiktok登录页面,输入用户名和密码,即完成整个oAuth2授权流程,并且在token失效之前,CIP会定时进行检查,在后台进行token刷新。</p>
<p>CIP数据库会有这样一条数据,为后续业务接口调用提供授权相关的信息:</p>
<pre><code>|&nbsp;id&nbsp;|&nbsp;project_code&nbsp;|&nbsp;app_code&nbsp;|&nbsp;shop_id&nbsp;|&nbsp;api_key&nbsp;|&nbsp;api_secret&nbsp;|&nbsp;token&nbsp;|&nbsp;token_invalid_date&nbsp;|&nbsp;refresh_token&nbsp;|&nbsp;refresh_token_invalid_date&nbsp;|
|&nbsp;--- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|&nbsp;1&nbsp;|&nbsp;factory-tiktok&nbsp;|&nbsp;tiktok&nbsp;|06944&nbsp;|&nbsp;67715&nbsp;|7e68f17b8&nbsp;|&nbsp;ROW&nbsp;|2025-01-22|&nbsp;ROW_6-gD&nbsp;|2122-12-0413:45:16|</code></pre>
<p>&nbsp;</p>
<h2>3.2. 支持流程编排</h2>
<p>一次数据传输定义为“任务流”,我们需要控制节点的执行顺序,支持逻辑转换和数据补全,逻辑转换比如时间的转换,外部电商的时间格式有很多种,我们需要转换成一种标准的格式,推到内部系统,数据补齐一般只是的是拉到外部数据后,会通过查询主数据去补充信息,转换成标准的数据格式,推到内部系统。</p>
<p>以下用V-Work中tiktok退款状态查询功能举例:</p>
<pre><code>[ &nbsp;
&nbsp; { &nbsp;
&nbsp; &nbsp;&nbsp;"code":&nbsp;"con-webhook", &nbsp;
&nbsp; &nbsp;&nbsp;"name":&nbsp;"1"
&nbsp; }, &nbsp;
&nbsp; { &nbsp;
&nbsp; &nbsp;&nbsp;"code":&nbsp;"tiktok.cancedDetail", &nbsp;
&nbsp; &nbsp;&nbsp;"name":&nbsp;"2", &nbsp;
&nbsp; &nbsp;&nbsp;"fieldMap": { &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"params": { &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"order_ids": [ &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"{#ib1.orderNo#}"
&nbsp; &nbsp; &nbsp; &nbsp; ] &nbsp;
&nbsp; &nbsp; &nbsp; } &nbsp;
&nbsp; &nbsp; } &nbsp;
&nbsp; }, &nbsp;
&nbsp; { &nbsp;
&nbsp; &nbsp;&nbsp;"code":&nbsp;"con-branch", &nbsp;
&nbsp; &nbsp;&nbsp;"name":&nbsp;"3", &nbsp;
&nbsp; &nbsp;&nbsp;"action":&nbsp;"{${#ob2.cancel_status#}=='CANCELLATION_REQUEST_PENDING'||{#ob2.cancel_status#}=='CANCELLATION_REQUEST_SUCCESS'||{#ob2.cancel_status#}=='CANCELLATION_REQUEST_COMPLETE'$}", &nbsp;
&nbsp; &nbsp;&nbsp;"resultMap": { &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"code":&nbsp;"200", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"data": { &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"status":&nbsp;1
&nbsp; &nbsp; &nbsp; }, &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"message":&nbsp;"SUCCESS", &nbsp;
&nbsp; &nbsp; &nbsp;&nbsp;"subCode":&nbsp;"10000"
&nbsp; &nbsp; } &nbsp;
&nbsp; } &nbsp;
]</code></pre>
<p>&nbsp;</p>
<h2>3.3 内置数据池存取方法,支持流程中节点对数据池共享访问</h2>
<p>任务流中每个节点的执行,即系统接口的方法调用,都会有输入输出参数,CIP会把每个节点的执行数据存储到流程数据池中,这样后续的节点,就可以对数据池数据进行访问,从而获取前面节点的执行数据,保证本节点能正常执行。当前定义了4种变量引用的方法:</p>
<ul>
<li>
<p><strong>接口输入字段:</strong>{# ih.xxx #}、{# ib.xxx #} 、{# ip.xxx #} 、ih = input-header,ib = input-body,ip = input-param ,当前请求执行关联的输入字段。</p>
</li>
<li>
<p><strong>接口输出字段:</strong>{# oh.xxx #}、{# ob.xxx #} 、oh = output-header,ob = output-body,当前请求执行关联的输出字段。</p>
</li>
<li>
<p><strong>项目授权账号:</strong>{# ad.xxx #},ad = auth-data,当前请求执行关联的授权账号和token信息。</p>
</li>
<li>
<p><strong>项目常量:</strong>{# pc.xxx #} ,pc = project-constant。</p>
</li>
</ul>
<p>以ib举例:ib表示从当前节点获取数据、ib3表示从别名为3的节点获取数据;ib.order.orderId表示获取ib的order对象的orderId字段值、ib.order表示获取ib的order对象、ib表示获取ib的所有字段值、ib表示获取ib列表中的第1条数据。</p>
<p>&nbsp;</p>
<h2>3.4 支持远程dubbo方法、本地方法、MQ、HTTP配置调用</h2>
<p>具体看下每种调用类型的配置方法。</p>
<p><strong>(1)Dubbo方法</strong></p>
<pre><code>{ &nbsp;
&nbsp; “application”: ”trade-center”, &nbsp;
&nbsp; “interfaceName":“com.vivo.tradecenter.EcomOrderApi”, &nbsp;&nbsp;
&nbsp; “method”: ”createOrder”, &nbsp;&nbsp;
&nbsp; “param”: [ &nbsp;
&nbsp; &nbsp; {# orderId #} &nbsp;
&nbsp; ] &nbsp;
}</code></pre>
<p>本地方法和RPC类似,主要用在对电商平台SDK的调用场景。</p>
<p><strong>(2)HTTP</strong></p>
<pre><code>{ &nbsp;
"url":&nbsp;"/wms/factory/outbound", &nbsp;
"body": { &nbsp;
&nbsp; &nbsp; "language":&nbsp;"{# language #}", &nbsp;
&nbsp; &nbsp;&nbsp;"serialNo":&nbsp;"{# serialNo #}", &nbsp;
&nbsp; &nbsp;&nbsp;"timeZone":&nbsp;"{# timeZone #}", &nbsp;
&nbsp; &nbsp;&nbsp;"sourceFrom":&nbsp;"{# sourceFrom #}", &nbsp;
&nbsp; &nbsp;&nbsp;"invokerSystem":&nbsp;"{# invokerSystem #}", &nbsp;
&nbsp; &nbsp;&nbsp;"requestBodyDTO":&nbsp;"{# requestBodyDTO #}"
&nbsp; }, &nbsp;
"param": {}, &nbsp;
"header": { &nbsp;
&nbsp; &nbsp; "accept":&nbsp;"application/json"
&nbsp; } &nbsp;
}</code></pre>
<p><strong>(3)MQ</strong></p>
<pre><code>{ &nbsp;
&nbsp; &nbsp; “topic”: “delivery_handle_result_topic”, &nbsp;
&nbsp; &nbsp; “tag": “outbound”, &nbsp;
&nbsp; &nbsp; “delayLevel": “1” &nbsp;
&nbsp; &nbsp; “body": { &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; “logistics_code": {# logisticsCode #} &nbsp;
&nbsp; &nbsp; } &nbsp;
}</code></pre>
<p>&nbsp;</p>
<h2>3.5 支持分支、循环、合并、webhook、数据存储和文件存储</h2>
<p>这些内置的能力,我们定义为“连接器”,可作为任务流配置的节点,同触发器、执行器配合,共同完成多个系统之间的集成,当前定义了以下几种类型的连接器:</p>
<img src="https://static001.geekbang.org/infoq/84/849bf141a420e22ca517be751b3462f3.jpeg">
<p>&nbsp;</p>
<h2>3.6 内置EL表达式语言</h2>
<p>表达式引擎并没有选择自研,主要是因为市面上有成熟好用的规则引擎,没必要重复造轮子,调研了几个规则引擎框架,最终选择了QLExpress作为基础引擎,在它基础之上,根据实际业务,进行扩展开发,CIP扩展的表达式,主要包括以下几大类:</p>
<img src="https://static001.geekbang.org/infoq/1a/1a58b159239fd41502627212bc2bbcbc.jpeg">
<p>&nbsp;</p>
<h2>3.7 异步流程执行</h2>
<p>同步任务指的就是遇到比较多的场景,系统集成实时返回结果。还有一种我们称之为异步任务,比如仓库出库结果,同步外部系统场景,履约系统抛出的是MQ出库结果消息,这个时候我们就要先接收下来,不能阻塞MQ,然后异步的将MQ消息转换适配后,推给外部对接系统。</p>
<p>异步任务可能出现在任何节点,都有可能:</p>
<ol>
<li>
<p data-number="1">针对MQ类型的触发流程,那任务流的第一个接口执行完成后,就需要commit,然后异步从第2个节点开始执行。</p>
</li>
<li>
<p data-number="2">外部推送的一些同步数据,先进行初步校验,校验通过后,就需要返回成功给外围,这时候可能已经执行了比如3个节点,那后续异步执行就要从第4个节点开始。</p>
</li>
</ol>
<p>即可以指定任何节点开始重试,但目前我们只有可能在第1个节点后和最后1个节点异步执行,所以限制node=first/last。</p>
<p>异步任务必须要具备重试的能力,所以需要能够指定重试次数和重试间隔:“count": 3,“interval": “1/2/3”。</p>
<pre><code>TaskFlowInvokeStrategyEnum&nbsp;strategyType&nbsp;=&nbsp;null; &nbsp;
//第一个节点执行后 &nbsp;
if&nbsp;(task.getExecutionStrategy().isFirstAfter()) { &nbsp;
&nbsp; &nbsp; strategyType = TaskFlowInvokeStrategyEnum.FIRST; &nbsp;
} &nbsp;
//最后一个节点执行前 &nbsp;
if&nbsp;(task.getExecutionStrategy().isLastBefore()) { &nbsp;
&nbsp; &nbsp; strategyType = TaskFlowInvokeStrategyEnum.LAST; &nbsp;
} &nbsp;
TaskFlowExecuteStrategyBO&nbsp;strategy&nbsp;=&nbsp;new&nbsp;TaskFlowExecuteStrategyBO(task, taskFlow, strategyType); &nbsp;
taskFlowExecuteStrategyDomain.insert(strategy); &nbsp;
mqPublisherFactory.doPublish(strategy, taskFlowTopic, task.getExecutionStrategy().getInterval(delayLevel));</code></pre>
<p>&nbsp;</p>
<h2>3.8 错误机制</h2>
<p>关于任务流(即某个系统间的集成任务)执行失败的控制机制,站在简化任务流配置方面考虑,即任务流中每个节点执行成功失败的判断,并没有放在任务流中通过分支条件去控制,我认为任务流的核心关注点是指定参与节点,节点主要指的是操作了某系统的某个方法,而不是有很多的判断配置,降低了任务流的可读性。当前错误码可以在2个层级进行定义:</p>
<ul>
<li>
<p><strong>应用层级:</strong>它的适用范围比较广,可影响本应用下的所有触发器和执行器。</p>
</li>
<li>
<p><strong>节点层级:</strong>仅影响某个触发器或者执行器。</p>
</li>
</ul>
<p>&nbsp;</p>
<p>目前遇到了2种返回情况,第一种是直接通过http的状态码,第二种是HTTP状态码为200,通过JSON数据返回,这种情况更常见。节点成功判断规则:</p>
<ul>
<li>
<p>配了执行器的httpSuccess和success,只看执行器配置,否则看应用的httpSuccess和success。</p>
</li>
<li>
<p>httpSuccess和success判断规则:</p>
<p>① httpSuccess和success都没配:如果http的status code为2XX,就认为成功,否则失败。</p>
<p>② 只配httpSuccess:以httpSuccess为准。</p>
<p>③ 只配success:如果http的status code为2XX,再与success进行比较,否则失败。</p>
<p>④ httpSuccess和success同时配:必须同时满足。</p>
</li>
</ul>
<p>&nbsp;</p>
<h1>四、应用</h1>
<p>从2024年2月份提出创意开始,并经过三四个月的规划,设计和开发后,最终现在已经推广半年多的时间里,当前已经能覆盖vivo分销的主要应用场景,使用数据情况:覆盖vivo分销核心业务场景(仓储管理系统对接执行订单出入库作业、财务系统对接完成结算过账、电商平台对接实现销售订单履约、分销商系统对接实现交易数据的共享等)、50+系统、25个项目、300+的集成场景、日调用量10万级,较正常开发预计节省人力50%以上。</p>
<p>&nbsp;</p>
<h1>五、总结和展望</h1>
<p>本文从作者实际痛点出发,到产生愿景,最后再到落地的全过程,并结合实例案例,介绍了一些核心设计思路,希望读者阅读后对vivo分销业务,能有一些了解,也希望能对读者在应用的认证鉴权、流程编排、低代码等方面有所启发。</p>
<p>&nbsp;</p>
<p>站在本平台规划起初的目标上,已经算基本完成了目标,但如果想进一步在部门或者公司层面进行推广,我们还需要进一步提高平台可视化和易操作性,因为当前可视化功能,还没有把配置语义转换成业务语义,而是直接把里面存储的语法暴露给开发人员去配置,最终目标是系统集成的开发,能够转化为系统集成的数据管理,暴露给不懂开发的人员去配置,这是未来要重点提升的方面。</p>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    分享 vivo 互联网技术干货与沙龙活动,推荐最新行业动态与热门会议。<br><br>
来源:https://www.cnblogs.com/vivotech/p/18949533
頁: [1]
查看完整版本: 三方系统集成(低代码)平台实践