掌桥专利:专业的专利平台
掌桥专利
首页

一种采用基于React Native的灰度热部署方式的营销中台系统

文献发布时间:2024-04-18 20:01:30


一种采用基于React Native的灰度热部署方式的营销中台系统

此专利为申请号202110119991.5一种基于层级串联技术的营销中台系统的分案申请

技术领域

本发明涉及软件开发技术领域,更具体的说,它涉及一种基于MQ分布式事务的层级串联营销中台系统。

背景技术

在大型的Saas软件内都需要构建强大的营销中台,以支持商户在线上、线下一体化营销中需要的灵活多变场景。软件应允许商户针对不同场景建立自定义规则,制定不同营销优惠策略。但优惠策略是多种多样的,特别是针对享受优惠需要“满足什么条件”这类适用性定义缺少强有力的表达方式。自然还会有其他的缺点,如难以进行灰度热部署进行系统的升级管理、系统在事务处理中难以实现分布式处理,营销类系统对于打印统计要求极高,目前难以实现快速的移动端打印等,缺少强有力的表达方式的问题,尤为突出。

现有软件中关于营销功能的技术方案实现一般有两种思路:

一种是简单的针对某些具体营销场景写死规则范式,比如只能定义“某个级别”会员针对“某类或某些品牌”商品享有折扣,这类配置存储在数据库表中,会固定引入会员、商品条件等字段,其命名和类型都会定死;其他相似的营销场景也需要不同的表和模块去实现。目前市面上大部分同类软件产品都处于这样的水平。此方式简单快速,易行易懂,但显然扩展性极差,如果需要变更条件或多引入一些条件则需要进行修改或重做,重复工作多,不能支撑Saas软件跨行业、多租户场景下快速变化的个性化需求。

另一种是基于某种通用的规则引擎,例如基于Drools规则引擎设计营销规则;这类规则引擎一般都很强大通用,可以支持复杂的算术、逻辑、比较表达式以及它们的组合和运算优先级,因此能够支持很灵活的营销条件定义和判断逻辑。然而规则引擎本身很复杂,需要脚本语言支持;相应的,应用层营销规则的配置和使用起来也都非常复杂,商户难以上手。另外规则引擎虽然强大,但有下面几个缺点:

一、无法提供简易的查询方式在多个规则中快速筛选出符合条件的规则,只能通过一个个验证是否通过进行筛选。

二、规则引擎能够支持算术、逻辑等表达式,但是普遍缺少一种树状表达方式,例如一个全国性商家针对华北地区的店铺进行冬款衣服打折,那么位于河北省(属华北地区)下面一个城市的店铺开了一个单子,该店铺是否满足该地域条件呢?这就需要引入层级表达式对层级化的成员进行判断是否具备包含关系。而且目前此类规制引擎运行时对计算资源的消耗大,在Saas软件高并发场景下,实时计算响应较慢,很影响客户使用。

发明内容

本发明克服了现有技术的不足,提供一种基于层级串联技术的营销中台系统。

本发明的技术方案如下:

一种基于层级串联技术的营销中台系统,包括营销条件模块和权益模块,具体包括如下步骤:

101)营销场景分析步骤:根据相应活动及链接入口,分析活动对应的营销条件模块和权益模块;营销条件模块进行分析相应活动的适用条件;

102)条件搭建步骤:根据营销条件模块分析的活动的适用条件,确认该活动需要的层级项数量,用层次来表述层级项内部的层级,通过设置相应接口实现本活动营销条件模块的调用;

103)权益确认步骤:权益模块根据步骤102)营销条件模块搭建的活动条件,给出相应的折扣权益或赠送适当礼包。

进一步的,层次从层级项内部从高到低设置至少一个层次;每个层次包括相应的至少一个成员,成员具有采用离散性、分层性,成员数量为多个时,还设置全范围特殊成员,其代表该层次所有成员。

进一步的,同一层级项内的下级成员位于上级成员范围内;不同层级项之间的成员相互独立。

进一步的,层级项下每个层次的成员的数据存储在数据库的关系表中,存储的数据结构类型采用层次关系和/或父子关系。

进一步的,相应接口包括层级项名称、层次的定义、顶层成员、某个成员的父成员、某个成员的下层成员列表、某个成员进行翻译,便于读取成员和成员关系;以java语言为例,定义如下:

其中Member的参考定义如下:

其中level的参考定义如下:

进一步的,步骤102)中多个层级项通过串联表达式生成代表不同规则的表达式。

进一步的,数据库的关系表中包括索引模块,索引模块包括规则元数据定义表和规则定义表;

规则元数据定义表,相应营销活动对应的层级项不大于十个,对每个层级项进行存储,若未达到十个,剩余层级项为空;

规则定义表,用于存储具体规则,包括关键字段、权重字段和涉及字段;其中权重字段用于当两条及以上规则同时满足活动条件时,由权重字段作为优先级决定使用哪条规则;每个层级项存储的成员数据为单个或多个,多个时采用逗号分隔。

进一步的,还包括规则检索模块,规则检索模块根据活动条件的每个层级项提取出对应的成员作为参数,根据这组参数成员去规则定义表中进行检索,若某条规则的全部层级项成员包含或等于传入的这组参数成员,则该规则命中;在检索出所有匹配的规则后,业务层根据权重决定选用权重最高的规则,或合并使用所有规则,最后根据权益模块里定义的优惠信息进行后续处理。

进一步的,还包括规则验证模块,其与规则检索模块相反,规则验证模块采用预先给定一组参数成员,与指定的一条层级项规则进行比较,验证其是否满足该规则。

本发明相比现有技术优点在于:本发明通过抽象出一组串联的层级项表达式概念来表达复杂多变的营销规则,进而实现基于层级项的规则检索和验证。把层级项概念应用于营销中台里的适用条件定义。

本发明通过引入层级项概念,把业务领域中的复杂信息结构化,化繁为简,便于应用开发人员和营销规则配置人员理解和操作。

应用开发人员在给定的概念模型和接口定义约束下,可以简单、一致地识别出具体的层级项对象并将其快速开发出来;层级项被定义出来后还可以被统一注册到层级项仓库中,从而可以在多种业务场景中重用。最终可以大大提高开发效率,并且可以很好地满足不断变化的营销需求。

开发人员一旦对层级项进行建模并注册后,运营人员就可以不依赖开发人员独立配置营销活动了。运营人员根据需要可以自由使用不同的层级项组合,自由地把一组层级项成员值组合成具体的活动规则;另外因为层级项天然具有层次特性,引入层次表达式可以具备更多的表达力。整个配置过程可以做到直观可视化,容易理解和操作。

本发明整个规则引擎比较轻量,借助于关系数据库成熟的数据检索技术,加上少量的内存计算,在Saas软件多租户超高并发的情况下也能做到线性、毫秒级响应。

附图说明

图1为本发明的灰度热部署自动化打包流程示意图;

图2为本发明的灰度热部署检查更新流程示意图;

图3为本发明的灰度热部署最优路径实例示意图;

图4为本发明的灰度热部署最短路径选择实例示意图;

图5为本发明的营销中台内的层级项示意图;

图6为本发明的层级项内部的层次示意图;

图7为本发明的层级的层次关系示意图;

图8为本发明的层级的父子关系示意图;

图9为本发明的规则验证流程图;

图10为本发明的分布式事务处理流程图;

图11为本发明的分布式事务实例图。

具体实施方式

下面详细描述本发明的实施方式,其中自始至终相同或类似的标号表示相同或类似的元件或类似功能的元件。下面通过参考附图描述的实施方式是示例性的,仅用于解释本发明而不能作为对本发明的限制。

本技术领域技术人员可以理解的是,除非另外定义,这里使用的所有术语(包括技术术语和科技术语)具有与本发明所属领域中的普通技术人员的一般理解相同的意义。还应该理解的是,诸如通用字典中定义的那些术语应该被理解为具有与现有技术的上下文中的意义一致的意义,并且除非像这里一样的定义,不会用理想化或过于正式的含义来解释。

各实施方式中提到的有关于步骤的标号,仅仅是为了描述的方便,而没有实质上先后顺序的联系。各具体实施方式中的不同步骤,可以进行不同先后顺序的组合,实现本发明的发明目的。

下面结合附图和具体实施方式对本发明进一步说明。

实施例1:

如图4至图9所示,一种基于层级串联技术的营销中台系统,包括营销条件模块和权益模块,因为活动及链接入口是很多的,譬如限时折扣、节日大促、会员关怀等;但只要它们涉及到的层级项类型和个数相同,则可以认为这些营销规则是同一类的。如图1中营销规则中的举例,其各自具有三个层级项的两种营销规则。因此当把层级项应用于营销中台优惠策略时,具体包括如下步骤:

101)营销场景分析步骤:根据相应活动及链接入口,分析活动对应的营销条件模块和权益模块;营销条件模块进行分析相应活动的适用条件。

102)条件搭建步骤:根据营销条件模块分析的活动的适用条件,确认该活动需要的层级项数量,具体层级项可以用hier关键字开头表示;用层次来表述层级项内部的层级,通过设置相应接口实现本活动营销条件模块的调用。

层次(level)从层级项内部,从高到低设置至少一个层次。例如商品层级项从高到低可以是“一级类目”、“二级类目”、“商品”层;地区层级项根据需要从高到低有"地市"、"区县"、"乡镇"等;时间维从高到低可以是“年”、“月”、“日”,也可以是“年”、“月”、“周”等层,具体如图2所示。

每个层次包括相应的至少一个成员,成员具有采用离散性、分层性,成员数量为多个时,还设置全范围特殊成员,其代表该层次所有成员。同一层级项内的下级成员位于上级成员范围内;反之上级成员包含下级成员。不同层级项之间的成员相互独立。例如地区层次上有:

[hierArea].[宁波市]

[hierArea].[杭州市]

[hierArea].[杭州市].[西湖区]

特别的还有一类特殊成员代表该层的所有取值范围,简称all值,例如[hierArea].[杭州市].[all]代表杭州下的所有区县。

103)权益确认步骤:权益模块根据步骤102)营销条件模块搭建的活动条件,给出相应的折扣权益或赠送适当礼包。

其中,层级项下每个层次的成员的数据存储在数据库的关系表中,存储的数据结构类型采用层次关系和/或父子关系。以地区层级为例,层次关系如图3所示,每个Level占用一个表字段。父子关系如图4所示,固定两个字段code、pcode表达出上下级关系,父子关系就是一个层次Level。

相应接口包括层级项名称、层次的定义、顶层成员、某个成员的父成员、某个成员的下层成员列表、某个成员进行翻译,便于读取成员和成员关系;实现层级项模型,包含一套层级和层次的接口和基类,业务层在识别和定义一个新的层级项时,可以二次开发快速实现一个新类。具体包含的层级和层次的接口和基类,以java语言为例,定义如下:

其中Member的参考定义如下:

其中level的参考定义如下:

自然,可以针对层次和父子两种存储结构类型,可以封装出对应的工具包方便应用层从表中读取成员和关系。

步骤102)中多个层级项通过串联表达式生成代表不同规则的表达式。即针对一个营销场景,识别出几个层级项,给每个层级项赋予一个成员值,这些成员值前后组合起来便形成一个表达式。层级表达式同时也定义了一条规则;通过设置不同成员值的组合可以生成代表不同规则的表达式。

例如,假设某商户下的会员折扣活动涉及到下面三个层级项及其层次定义(层次按从高到低次序):

会员(hierMember),有两个层次:

levelCustomer(会员级别)

levelMember(会员个人)

门店(hierShop)有三个层次:

levelArea(大区)

levelCity(城市)

levelShop(门店)

商品(hierSpu)有两个层次:

levelBrand(商品品牌)

levelSpu(商品)

根据上述层级结构,有下面一组规则定义:

规则一,表示钻石级会员在武林店购买七匹狼和雅戈尔品牌服装时可以享受某折扣,则层级表达式为:

{[hierMember].[钻石会员],[hierShop].[华东区].[杭州市].[武林店],{[hierSpu].[七匹狼],[hierSpu].[雅戈尔]}}

规则二:表示白银级会员在武林店购买所有品牌服装时可以享受某折扣,则层级表达式为:

{[hierMember].[白银会员],[hierShop].[华东区].[杭州市].[武林店],[hierSpu].[所有品牌]}

数据库的关系表中包括索引模块,索引模块包括规则元数据定义表和规则定义表;建立索引模块,能查询方便且效率高。

其中,规则元数据定义表,相应营销活动对应的层级项不大于十个,对每个层级项进行存储,若未达到十个,剩余层级项为空,即未用到的多定义的层级项为空即可。

规则定义表,用于存储具体规则,包括关键字段、权重字段和涉及字段;其中权重字段用于当两条及以上规则同时满足活动条件时,由权重字段作为优先级决定使用哪条规则;每个层级项存储的成员数据为单个或多个,多个时采用逗号分隔。

还包括规则检索模块,规则检索模块根据活动条件的每个层级项提取出对应的成员作为参数,根据这组参数成员去规则定义表中进行检索,若某条规则的全部层级项成员包含或等于传入的这组参数成员,则该规则命中;在检索出所有匹配的规则后,业务层根据权重决定选用权重最高的规则,或合并使用所有规则,最后根据权益模块里定义的优惠信息进行后续处理。

层级项表达式定义的规则举例如下,当某客户在店内下单时,软件应用层可以知道当前上下文场景下“客户是谁”(如:张三,会员级别是白银)、“在哪个门店下单”(如:武林店)以及“购买了什么商品”(如:JB002款),根据这些上下文信息组装成成员参数组,其结构如下:

{[hierMember].[白银会员].[张三],[hierShop].[华东区].[杭州市].[武林店],[hierSpu].[九牧牌].[2020年夏季休闲男裤JB002款]}

使用该参数成员组去上述“规则定义表”中进行检索可以发现符合上述的“规则二”。因为是关系数据库,直接使用SQL语句即可实现规则检索的算法,sql语句的核心片段如下:

若hiern_value字段里存储的是用逗号分隔多个成员值,表示满足其中一个成员值亦可。以Mysql数据库为例,可以用数据库的find_in_set函数代替“=”表达式即可,如:

还包括规则验证模块,如图9所示,其与规则检索模块相反,规则验证模块采用预先给定一组参数成员,与指定的一条层级项规则进行比较,验证其是否满足该规则。

实施例2:

如图1至图11所示,一种应用于营销的新式管理系统。对于营销的系统搭建包括营销条件模块和权益模块,因为活动及链接入口是很多的,譬如限时折扣、节日大促、会员关怀等;但只要它们涉及到的层级项类型和个数相同,则可以认为这些营销规则是同一类的。如图1中营销规则中的举例,其各自具有三个层级项的两种营销规则。因此当把层级项应用于营销中台优惠策略时,具体包括如下步骤:

101)营销场景分析步骤:根据相应活动及链接入口,分析活动对应的营销条件模块和权益模块;营销条件模块进行分析相应活动的适用条件。

102)条件搭建步骤:根据营销条件模块分析的活动的适用条件,确认该活动需要的层级项数量,具体层级项可以用hier关键字开头表示;用层次来表述层级项内部的层级,通过设置相应接口实现本活动营销条件模块的调用。

层次(level)从层级项内部,从高到低设置至少一个层次。例如商品层级项从高到低可以是“一级类目”、“二级类目”、“商品”层;地区层级项根据需要从高到低有"地市"、"区县"、"乡镇"等;时间维从高到低可以是“年”、“月”、“日”,也可以是“年”、“月”、“周”等层,具体如图2所示。

每个层次包括相应的至少一个成员,成员具有采用离散性、分层性,成员数量为多个时,还设置全范围特殊成员,其代表该层次所有成员。同一层级项内的下级成员位于上级成员范围内;反之上级成员包含下级成员。不同层级项之间的成员相互独立。例如地区层次上有:

[hierArea].[宁波市]

[hierArea].[杭州市]

[hierArea].[杭州市].[西湖区]

特别的还有一类特殊成员代表该层的所有取值范围,简称all值,例如[hierArea].[杭州市].[all]代表杭州下的所有区县。

103)权益确认步骤:权益模块根据步骤102)营销条件模块搭建的活动条件,给出相应的折扣权益或赠送适当礼包。

其中,层级项下每个层次的成员的数据存储在数据库的关系表中,存储的数据结构类型采用层次关系和/或父子关系。以地区层级为例,层次关系如图3所示,每个Level占用一个表字段。父子关系如图8所示,固定两个字段code、pcode表达出上下级关系,父子关系就是一个层次Level。

相应接口包括层级项名称、层次的定义、顶层成员、某个成员的父成员、某个成员的下层成员列表、某个成员进行翻译,便于读取成员和成员关系;实现层级项模型,包含一套层级和层次的接口和基类,业务层在识别和定义一个新的层级项时,可以二次开发快速实现一个新类。具体包含的层级和层次的接口和基类,以java语言为例,定义如下:

其中Member的参考定义如下:

其中level的参考定义如下:

自然,可以针对层次和父子两种存储结构类型,可以封装出对应的工具包方便应用层从表中读取成员和关系。

步骤102)中多个层级项通过串联表达式生成代表不同规则的表达式。即针对一个营销场景,识别出几个层级项,给每个层级项赋予一个成员值,这些成员值前后组合起来便形成一个表达式。层级表达式同时也定义了一条规则;通过设置不同成员值的组合可以生成代表不同规则的表达式。

例如,假设某商户下的会员折扣活动涉及到下面三个层级项及其层次定义(层次按从高到低次序):

会员(hierMember),有两个层次:

levelCustomer(会员级别)

levelMember(会员个人)

门店(hierShop)有三个层次:

levelArea(大区)

levelCity(城市)

levelShop(门店)

商品(hierSpu)有两个层次:

levelBrand(商品品牌)

levelSpu(商品)

根据上述层级结构,有下面一组规则定义:

规则一,表示钻石级会员在武林店购买七匹狼和雅戈尔品牌服装时可以享受某折扣,则层级表达式为:

{[hierMember].[钻石会员],[hierShop].[华东区].[杭州市].[武林店],{[hierSpu].[七匹狼],[hierSpu].[雅戈尔]}}

规则二:表示白银级会员在武林店购买所有品牌服装时可以享受某折扣,则层级表达式为:

{[hierMember].[白银会员],[hierShop].[华东区].[杭州市].[武林店],[hierSpu].[所有品牌]}

数据库的关系表中包括索引模块,索引模块包括规则元数据定义表和规则定义表;建立索引模块,能查询方便且效率高。

其中,规则元数据定义表,相应营销活动对应的层级项不大于十个,对每个层级项进行存储,若未达到十个,剩余层级项为空,即未用到的多定义的层级项为空即可。

规则定义表,用于存储具体规则,包括关键字段、权重字段和涉及字段;其中权重字段用于当两条及以上规则同时满足活动条件时,由权重字段作为优先级决定使用哪条规则;每个层级项存储的成员数据为单个或多个,多个时采用逗号分隔。

还包括规则检索模块,规则检索模块根据活动条件的每个层级项提取出对应的成员作为参数,根据这组参数成员去规则定义表中进行检索,若某条规则的全部层级项成员包含或等于传入的这组参数成员,则该规则命中;在检索出所有匹配的规则后,业务层根据权重决定选用权重最高的规则,或合并使用所有规则,最后根据权益模块里定义的优惠信息进行后续处理。

层级项表达式定义的规则举例如下,当某客户在店内下单时,软件应用层可以知道当前上下文场景下“客户是谁”(如:张三,会员级别是白银)、“在哪个门店下单”(如:武林店)以及“购买了什么商品”(如:JB002款),根据这些上下文信息组装成成员参数组,其结构如下:

{[hierMember].[白银会员].[张三],[hierShop].[华东区].[杭州市].[武林店],[hierSpu].[九牧牌].[2020年夏季休闲男裤JB002款]}

使用该参数成员组去上述“规则定义表”中进行检索可以发现符合上述的“规则二”。因为是关系数据库,直接使用SQL语句即可实现规则检索的算法,sql语句的核心片段如下:

若hiern_value字段里存储的是用逗号分隔多个成员值,表示满足其中一个成员值亦可。以Mysql数据库为例,可以用数据库的find_in_set函数代替“=”表达式即可,如:

还包括规则验证模块,如图9所示,其与规则检索模块相反,规则验证模块采用预先给定一组参数成员,与指定的一条层级项规则进行比较,验证其是否满足该规则。

本系统中对于事务的实现采用基于MQ的分布式事务方法,包括事务消息服务模块和事务消息客户端插件模块。

事务消息服务模块包括接收消息、提交/回滚消息和消息检查处理;

接收消息是事务消息服务模块提供的一个接收消息接口,供事务消息服务模块的事务发起端调用;事务发起端调用接收消息接口后,事务消息服务模块会缓存消息数据到缓存服务器;

提交/回滚消息由事务消息服务提供提交/回滚消息接口,供事务消息服务模块的事务发起端调用;事务发起端调用提交消息接口后,事务消息服务从缓存服务器取出消息数据,发送数据到MQ服务器,发送成功后,从缓存服务器删除消息数据;事务发起端调用回滚消息接口后,事务消息服务从缓存服务器删除消息数据;

消息检查处理,事务发起端调用事务消息服务的接收消息接口后,如果发生意外没有调用事务消息的提交/回滚消息接口,消息数据将不会转发和删除,为避免这种情况造成数据不一致,事务消息服务启动定时任务,定时检查没有及时转发和删除的消息;检查到存在超时未处理的事务消息,回调事务发起端接口,确认发起端本地事务是否成功完成,成功时提交消息,失败则回滚消息;

事务消息客户端插件模块,实现事务消息客户端插件嵌入到事务发起端和事务接收端。

事务消息客户端插件模块在事务发起端拦截spring本地事务操作,在spring本地事务提交或回滚操作前后进行事务消息相关处理;

spring本地事务提交前:事务发起端通过异步方式调用事务消息服务接收消息接口,实现事务消息客户端插件在spring本地事务提交前检查接收消息接口是否调用成功,成功时,正常提交事务;如果接收消息接口调用失败,则回滚本地事务;

spring本地事务提交后:调用事务消息服务提交消息接口;

spring本地事务回滚后:调用事务消息服务回滚消息接口。

事务消息客户端插件模块在事务接收端起到辅助接收端检查消息是否已处理,避免重复处理消息;如果消息不能重复消费,事务消息客户端插件接收到消息时,在本地表中写入事务消息ID,通过检查事务消息ID是否存在,来确保消息仅消费一次。

如图11所示,以会员充值送积分业务为例:

业务需求为会员每充值1元,送1积分。用户进入充值子系统,通过接收消息、提交/回滚消息和消息检查处理,精准的将消息进行传递,并经行了多次消息的确认,以确保信息的准确。

本系统的部署以及后续的升级管理采用基于React Native的灰度热部署方式,其包括gitlab runner模块、web端模块、服务端模块和客户端模块。

gitlab runner模块用于执行打包任务,通过开源代码托管平台,部署基于该平台的运行服务,该运行服务通过相应执行任务文件进行运作,任务文件实现执行的任务,其包括依赖下载、打包;任务文件通过开源代码托管平台相应的对外接口进行触发。即gitlab是免费的开源代码托管平台,可私有部署。runner是基于gitlab的一种运行服务,该服务通过项目中.gitlab-ci.yml文件执行任务,该文件可编写各种执行任务,比如npm包下载相应依赖、打包等。当runner被触发时,runner检查项目中的.gitlab-ci.yml文件,执行相关任务。runner触发方式有多种,比如通过监听某个分支的代码变更,比如通过gitlab api触发,一般通过采用gitlab api触发。

web端模块用于灰度发布,触发gitlab runner模块的打包功能,打包结束后会将包上传到服务器,完成一次打包任务;服务器收到打包文件后,会将这次发布的版本及灰度方式存储到数据库中,完成一次应用发布。

例如有一个优惠券的功能点,该功能点代码在release/coupon分支,当需要发布该功能点时,在web端选择release/coupon分支,填写发布版本,选择灰度方式(按比例:比如30%;按系统版本:比如android 8、按网络环境等),点击发布,此时调用gitlab apihttps://gitlab.example.com/api/v3/projects/1/pipeline?ref=release/coupon。即可触发gitlab runner检查项目中配置文件.gitlab-ci.yml,执行打包任务,打包结束后会将包上传到服务器模块,即可完成一次打包任务。服务器模块收到打包文件后,会将这次发布的版本及灰度方式存储到数据库中,完成一次应用发布。

服务端模块用于存储、下发打包的执行任务文件JavaScript;服务端模块包括数据库表packages和packages_diff,其中packages表记录每次版本的发布,信息包括包下载链接、版本号、灰度方式、是否存在diff包、是否可下载等。packages_diff表记录每次发布的diff后的文件信息(如果有)即差异性文件包。当服务端收到gitlab runner模块上传的包后,检查packages表是否已存在同版本的包,如果不存在,记录该次发布的相应信息到表packages;如果存在,则利用文本差异方法生成差异化后的内容,将差异后的内容保存到旧包进行替换,同时记录到packages_diff表,完成一次差异化过程。

当客户端模块的请求到达时(客户端模块的请求包括版本号、系统版本、网络条件、地区等信息),服务端模块根据请求携带的版本号检查packages表,如果不存在对应的版本号,则返回无更新包;如果存在对应的版本号,检查是否满足灰度条件(例如灰度条件为android系统版本大于8,当请求携带的信息android系统版本为7时则不满足灰度条件,android系统版本为9时则满足灰度条件。),不满足灰度条件时返回无更新包,满足灰度条件时,检查是否存在差异包,不存在,下发完整的包下载链接,存在,从表packages_diff中获取下载链接返回。

当从web端模块暂停某次灰度发布时,服务端模块会将packages表对应的那条发布记录是否可下载字段标记为否,此时当客户端模块请求触达时返回无更新包。

客户端模块,每次客户端模块启动时,请求接口检查更新,服务器模块根据接口参数,返回相关结果,客户端模块拿到返回结果后;如果无更新包,则结束流程;如果有更新包,下载该包;下载完成后,判断是否为差异包,如果不是差异包,保存该包到本地,同时将该包标记为current_package,将正在运行的包标记为previous_package;如果是差异包,则利用文本差异方法合并差异包内容到现有包,并保存到本地,同时将保存的包标记为current_package,将正在运行的包标记为previous_package。其中,差异包为下载的包信息里面携带了是否为差异包的特有标识信息。

下次启动获取标记为current_package的包运行,如果首次运行current_package包崩溃,则删除current_package标记的包,同时将标记为previous_package的包更改为current_package,供下次启动运行。

综上各React Native产品线(如连锁日记、笑铺日记、商陆微店等)均可接入本方案系统,当有新的功能点或者bug需要发布时,即可在本方案系统上操作,快速完成一次热部署。当新的功能点发布后,用户反馈有bug,可通过暂停下发功能,减少对大量用户的影响。

具体的,其中文本差异方法采用处理步骤少,且处理上删除后新增,比新增后删除多;其中,通过图的最短路径搜索问题来进行最优选择。即把文件的头部相同的最长子串剔除;对于尾部,以较短的字符串为依据求最长子串,后剔除最长子串,文件剩下的部分再做diff包处理。

文本差异方法中包括delete,insert,equal三种操作,delete表示删除操作,insert表示插入操作,equal表示相同进行保留。通过处理步骤少,且处理上删除后新增,比新增后删除多的原则进行处理。具体如源文本为src=ABCABBA,目标文本为dst=CBABAC,则由源文本到目标文本的方式会有多种:

方式一:-A、-B、C、-A、B、+A、B、A、+C(-代表delete,+代表insert,不添加符号表示equal);

方式二:-A、+C、B、-C、A、B、-B、A、+C;

方式三:+C、-A、B、-C、A、B、-B、-A、+A、+C;

方式一可用集合表示为:

Steps=[“deleteA”,“deleteB”,“equalC”,“deleteA”,“equalB”,“insertA”,“equalB”,“equalA”,“insertC”],共九步完成转换。

方式二可表示集合为:

Steps=[“deleteA”,“insertC”,“equalB”,“deleteC”,“equalA”,“equalB”,“deleteB”,“equalA”,“insertC”],共九步完成转换。

方式三可表示集合为:

Steps=[“insertC”,“deleteA”,“equalB”,“deleteC”,“equalA”,“equalB”,“deleteB”,“deleteA”,“insertA”,“insertC”],共十步完成转换。

显然方式一比方式二要直观,即删除后新增,比新增后删除要好,同时转换步骤最少。因此符合文本差异方法。其中判定如方式一与方式三中,寻找最短的转换步骤显然是典型的最短路径搜索问题,仍以上面转换为例,构造如图3所示的,横轴为src内容,纵轴为dst内容,图中每一条左上角到右下角的路径,都表示一个diff步骤,向右表示delete(删除),向下表示insert(新增),对角线表示equal(原内容保持不动)。

选择路径如下:

(0,0)->(1,0)

(1,0)->(2,0)->(3,1)

(3,1)->(3,2)->(4,3)->(5,4)

(5,4)->(6,4)->(7,5)

(7,5)->(7,6)

路径代表的diff步骤为:-A、-B、C、+B、A、B、-B、A、+C。

利用上述路径成功将src转换到dst,但不一定是步骤最少的那条路径,因此需要通过利用动态规划及Myers算法思想来寻找路径,具体如下:

首先,定义参数d和k,d代表路径的长度,k代表当前坐标x-y的值。定义一个最优坐标,最优坐标表示d和k值固定的情况下,x值最大的坐标。x越大,表示向右走的多,进行了更多的优先删除操作。

具体从坐标(0,0)开始,此时,d=0,k=0,然后逐步增加d,计算每个k值下对应的最优坐标。因为每一步要么向右(x+1),要么向下(y+1),对角线不影响路径长度,所以,当d=1时,k只可能有两个取值,要么是1,要么是-1。

当d=1,k=1时,最优坐标是(1,0)。

当d=1,k=-1时,最优坐标是(0,1)。

因为d=1时,k要么是1,要么是-1,当d=2时,表示在d=1的基础上再走一步,k只有三个可能的取值,分别是-2,0,2。

当d=2,k=-2时,最优坐标是(2,4)。

当d=2,k=0时,最优坐标是(2,2)。

当d=2,k=2时,最优坐标是(3,1)。

以此类推,直到我们找到一个d和k值,达到最终的目标坐标(7,6)。建立如图4所示的横轴代表d,纵轴代表k,中间是最优坐标,从中可知当d=5,k=1时,到达了目标坐标(7,6),因此,最短的直观的路径就是(0,0)->(1,0)->(3,1)->(5,4)->(7,5)->(7,6),对应的diff包如下:-A、-B、C、+B、A、B、-B、A、+C。如上所述当d=5时,所有k对应的最优坐标,必须先要知道d=4时所有k对应的最优坐标,要知道d=4时的答案,必须先求解d=3,以此类推即可得到最短路径。

在具体软件灰度发布过程中,由于热部署打包的js代码字符串,前后两次热部署很大程度上,大部分代码都是一样的,仅有少部分的改动,因此会先做一个掐头去尾操作,把头部相同的最长子串剔除;对于尾部,以较短的字符串为依据求最长子串,后剔除最长子串,剩下的再做diff包过程,这样还能加速diff包过程。

如上一次的热部署js代码如下的话:

yr=v.create({app:{marginHorizontal:"auto",width:500}}),br=vr;Un.registerComp onent("App",(function(){return br})),Un.runApplication

("App",{rootTag:document.getElementById("react-root")})}]);

后因产品需求变更,宽度由原来的500改成308,则更改后的js代码为:

yr=v.create({app:{marginHorizontal:"auto",width:308}}),br=vr;Un.registerComp onent("App",(function(){return br})),Un.runApplication

("App",{rootTag:document.getElementById("react-root")})}]);

因为头尾有很多重复的字符串,为了加速操作,头尾相等,记相应的过程为equal。假设头部变换记为Step1,中间不相等的变换记为Step2,尾部相等的部分变换记为Step3。

Step1 equal(0,48).其中0,48代表两段代码从起始位置到字符串长度为48的位置均相等。

Step2

Step3 equal(51,300)其中51,300代表两段代码从位置51到结尾均相等(假设字符串长度为300)。

那么现在求出Step2即从src=500到dst=308的最少变换步骤即可,利用上文描述的动态规划思想得到最少步骤描述为:-5、+3、0、-0、+8。记为Step2=[delete(49,’5’),insert(49,’3’),equal(50,50,‘0’),delete(51,‘0’),insert(51,’8’)]。则整个变换步骤如下:Step=[equal(0,48),delete(49,’5’),insert(49,’3’),equal(50,50,‘0’),delete(51,‘0’),insert(51,’8’),equal(51,300)]。其中delete、insert第一个参数代表操作字符串对应的字符位置,第二个参数代表操作的字符。equal第一个和第二个参数代表操作子串的起始和终止位置,第三个参数为具体操作字符(可以没有)。Package diff表文件记录的即是这样的变化步骤,客户端不需要每次下载完整的热部署代码,下载这样的diff包文件,根据diff包文件,即可得到完整的代码。

在整个营销中打印作为必不可少的功能,而目前在不同终端(iOS、Android等)要各自实现解析数据成打印指令的逻辑,造成的重复工作,且维护成本很高,因此为了方便打印本系统还集成了打印模版的可视化编辑方法,尤其在客户使用端,为了便于使用和精简软件,本系统部分功能以移植到微信小程序中,而可视化模版编辑功能就依托与微信小程序实现。因为在PC端已经有完整的打印实现方式,而移动端则很难实现有效快捷的打印。可视化模版编辑功能除了可以自定义编辑模版之外,还预置了一大批丰富的标准模版。可视化编辑功能的技术通过React Hooks配合微信MovableArea、MovableView组件实现。其中MovableArea、MovableView组件为物料提供了基础的移动能力,而通过React useEffectHook实现了数据的双向绑定,将视图与数据绑定起来,为后续实际打印打好基础。不管条码还是普通文本,都支持自定义输入(静态)以及数据读取(动态)的方式,可以按需选择。

编辑好模版之后模版数据会保存在打印中心服务端,后续打印时前端只需要传递模版id以及对应的货品数据,打印中心在收到请求后,会先对模版进行预解析,遇到需要读取数据的部分,则会从请求中的货品数据去读取并填充到对应的位置,最终解析成打印指令返回给前端。前端接受到打印指令后,无需任何多余动作,直接将指令传输给打印机进行打印操作。整个过程简单又迅速。

本系统的终端处还进行了网络最佳线路优化,终端启动时先从服务中心点获取多条线路缓存在本地服务端提供测速服务,先检测所有一级入口,选不出线路再选二级,一二级主要区别在于带宽/稳定性/可靠性。在终端加设了静态变量和保护时间(4秒*2=8秒)防止最佳线路的重复测。线路测试的发起采用并发测速,对于连接、读、写均可在2秒内完成,最差4秒可完成一次最佳线路选择。当等待所有测速线程完成,选择出最佳线路后,会以最快的速度更新到全局变量。其中这只在前台出现网络不给力提示后,才会触发进行最优线路检测,而检测是异步的,其不会影响主业务。不会大量增加现有互联网负担,用简单的常规的客户端选择算法即可实现。

以上所述仅是本发明的优选实施方式,应当指出,对于本技术领域的普通技术人员,在不脱离本发明构思的前提下,还可以做出若干改进和润饰,这些改进和润饰也应视为本发明保护范围内。

相关技术
  • 一种基于合成树脂和ITO薄膜的宽带超材料吸波器
  • 一种基于水层的可调谐光学透明宽带超材料吸波器
技术分类

06120116557984