业务
根据数据团队和导航团队的道路数据发布/上线版本号与上线环节信息,对其发布/上线成功与否进行判定和统计,发布日报和周报,并在周报中计算出当周发布/上线成功率
程序整体结构
先对来自外部数据库/接口的发布与上线信息按照需求所定的规则进行处理,生成约定好的中间数据(json 格式),再利用模板引擎将数据生成为HTML,继而发送
实现细节
-
周报与历史日报内容同步
由于发布/上线版本号与上线环节信息均来自外部数据库/接口,故无法确保这些信息的时不变性,有可能会导致周报与日报信息不一致。因此需对已查询信息进行缓存。所采取的缓存策略是,当生成日报中间数据时,将该中间数据(json 字符串)存入数据库,对应存入的还有该数据的有效时间(即被查询和计算的时刻)。由于需求变更可能会导致中间数据格式发生改变,使历史数据不可用,引入了校验码字段。校验码的生成策略是,对该被存入的中间数据进行广搜,将每层 key 按照字典序排序,下一层搜索按照上一层的 key 的排序顺序进行搜索,将每层间加一个分隔符,然后拼接为字符串,取其 md5,作为校验码。这样当每天产生周报时,只需根据当天日报数据计算出校验码,然后使用该校验码比对数据库中缓存的校验码,即可知道缓存数据是否可用。如果数据不可用,再去外部接口和数据库查找并生成历史数据。 -
多机部署
为了确保服务的稳定性,即每天都能成功发送邮件,防止服务器挂掉导致服务中断,故采用多机部署策略。但多机部署可能会导致每天发送的邮件数大于一封,为防止这种情况的发生,引入分布式锁。该分布式锁利用数据库实现,即将每天某刻发送邮件的行为抽象成一个任务,该任务包含关于发送这封邮件的所有信息,如应在几点发送、发送对象等,其中加入一个过期时间字段。当程序开启事务查询该任务信息,若发现过期时间大于当前时间,说明有进程正在执行这个任务,或是未到执行该任务的时间,遂程序结束;若发现过期时间小于当前时间,则该进程拿到执行任务的权限,更新该字段为第二天应发邮件的时间,接着继续执行。当某一拿到执行任务权限的进程在后续步骤中抛出不可容忍的异常时(如数据库异常),更新过期时间为当前时间并向管理员发送报警邮件。出现可容忍异常时,继续任务并发送报警邮件。 -
线上测试
由于线上运行时可能会出现不可预期的问题,故加入多任务支持,允许在正式邮件发送前先尝试向管理员发送邮件,这样即使在发送邮件时出现异常,管理员也可收到报警邮件进而进行紧急处理。同时在任务表中留有增量信息测试接口,即通过对该字段的修改可以控制邮件中数据的条数,即方便测试又为可能出现的生成月报等临时需求提供了便利。 -
用户数据与业务逻辑低耦合
为了便于增加/删除/修改发送任务、为导航方提供应上线版本干预和失败原因汇报入口,编写了简易的用户数据管理系统。前端使用 Webpack + Vue + ElementUI,后端使用 PHP。
总结
业务逻辑上虽然比较繁琐——发布/上线失败判定方式、三种成功率计算方式、失败环节负责人判定方式、对人为干预应上线版本所产生的影响的处理方式——其中一些逻辑相互依赖又相互影响,比较考验中间数据的格式的合理性,但仍算作一般难度的业务。本项目的难点在于确保服务的稳定性。数据库异常、接口异常、服务器挂掉、接口数据格式变更、无法确保生数据的时不变性这些不可控的外部因素都会影响服务的稳定性。因此,在多方面采取一些有效手段来抵抗不安因素是本项目的核心。