分布式系统解耦模式:用事件代表时间触发Cron计划任务

栏目: 后端 · 发布时间: 5年前

内容简介:计划任务一般都喜欢使用Cron作业来完成,比如使用spring scheduler或Quartz,本模式推荐使用黑盒式的不可知事件替代Cron作业。许多业务流程涉及需要在将来执行的某些操作或工作或工作负载。它可以是一次性动作或重复动作,可以安排在特定日期(例如圣诞节),重复日期(月的最后一个工作日)或超时(从现在起30天)。

计划任务一般都喜欢使用Cron作业来完成,比如使用spring scheduler或Quartz,本模式推荐使用黑盒式的不可知事件替代Cron作业。

问题

许多业务流程涉及需要在将来执行的某些操作或工作或工作负载。它可以是一次性动作或重复动作,可以安排在特定日期(例如圣诞节),重复日期(月的最后一个工作日)或超时(从现在起30天)。

我们希望保持整个流程的领域逻辑在单个(微)服务中很好地隔离,因此这也是此操作的逻辑所在。但是有一小部分逻辑不在这项服务中:就是事实执行需要进行,以及何时需要进行。

Cron是最麻烦的:它只适用于重复操作,并且外部 工具 几乎不能控制。 在大型系统中,cron文件可能造成巨大的混乱 。更现代的解决方案允许我们通过在代码中调用API来安排使用,这样可将逻辑移动到我们自己的服务中。但从根本上说,调度程序仍然是一个单独的服务,但是它涉及到知识比它应该知道的会更多。使用DDD术语,我们业务流程的无所不在的语言在此服务中泄漏。我们的系统中必须有更多类型的元素和更多的可移动部件。

解决

思维转换是: 将时间流逝视为另一个领域事件,就像所有其他事件一样 。毕竟,如果我们将领域事件定义为与业务相关的事件的粒度时间点,比如下一个工作日,月或季度。

在新的设计中,cron或调度程序会定期发出普通的时间段事件,例如DayHasPassed {date}午夜事件或一个 QuarterHasPassed {year, quarter}。所有感兴趣的服务都会收听此事件。他们可以通过执行操作,增加计数器,或通过查询某个数据库并按日期过滤来对其做出反应,以查找有一些工作要做的项目。

举例

时间管理着一切,有用的示例:可计费小时,订阅,资源使用,租赁,累积利息,付款,报告,工资,维护计划以及所有循环。

在发票到期日,我们需要向客户发送提醒。在旧设计中,我们可以设置一个调用的cron作业CheckForOverdueInvoices;在新设计中,cron DayHasPassed每隔午夜就产生一次,在InvoiceDebtCollection中监听DayHasPassed。

每当此事件到达时,InvoiceDebtCollection查询SELECT * FROM Invoice AS i WHERE DATEDIFF(i.dueDate, NOW()) >= 30。它可以直接发送提醒,但更好的方法是发出新InvoiceBecameOverdue事件。

现在,该服务可以收听自己的事件并发送提醒。其他服务也可以对InvoiceBecameOverdue 做出反应,例如调整收入预测或暂停帐户。

时间流逝事件也可以使用在更具特定领域。纳斯达克的盘前交易时间为04:00至09:30,然后是正常交易时间至16:00,盘后交易时间为20:00。假期没有交易。服务可以为每个启动和关闭生成事件,可以由许多感兴趣的服务使用。

优点

在上面的示例中,事件日志将显示:

CustomerWasInvoiced
DayHasPassed
DayHasPassed
...
InvoiceBecameOverdue
ReminderWasSent
AccountWasSuspended

使用时间元素编写业务流程测试非常优雅:

场景: If no payment is received after 15 days, we suspend the account
Given CustomerWasInvoiced
  And DayHasPassed 
  And DayHasPassed 
  And (...) 
 When DayHasPassed
 Then InvoiceBecameOverdue
  And AccountWasSuspended 
  
场景: If payment is received in time, we do nothing
Given CustomerWasInvoiced
  And DayHasPassed 
  And DayHasPassed 
 When PaymentWasMade
 Then Nothing        

更重要的是,这是一种很好的反应方法。当服务将命令发送到另一个服务时,它需要知道该其他服务接受该命令。当我们所做的只是发送通用时间事件通道时,调度程序不需要知道谁在听,消费者应该如何反应,或者是否还有任何服务可以监听。所有决策和领域知识都归接收者所有。这是很好的脱钩。

它也是时间解耦:调度程序可以将此时间通道事件放在队列中,并且此时消费者是否可用来处理事件并不重要。尽管如此,消费者可能会停顿几天,然后只需赶上并处理DayHasPassed队列中的所有事件。

在事件采购中,您只需将DayHasPassed事件存储在事件存储中,这样您就可以完全按照时间发生的方式回放整个历史记录,而不依赖于外部源。

时间事件和其他领域事件类型使用完全一样的格式和协议,通过与其他所有内容相同的消息传递基础结构发送它 这使得该模式在实现方面非常便宜。

弱点

原来在另一个其他地方上存在的一些领域知识:用于计算何时需要发生的域逻辑,例如“每月10日”,现在已经有效地从cron或调度程序转移到服务中。在实践中,这不是什么大不了的事,因为你可以找到时间库来为你完成工作。从好的方面来说,“除了周末,满月期间或年度办公室聚会期间,”每个月的第10个月“都是调度员无论如何也不会为你做的事情。

值得注意的是,您不希望将时间段事件模式用于实时系统。我们可以轻松地实现每年365个DayHasPassed事件,但对于处理几分钟或几秒或更短时间的系统,这是不可行的。幸运的是,对于 程序员 而言,在大多数企业中,“立即”一词意味着“在工作日结束时”,或“在本周末”,或“在事情发生的月份之后的季度结束之前” 。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTML Dog

HTML Dog

Patrick Griffiths / New Riders Press / 2006-11-22 / USD 49.99

For readers who want to design Web pages that load quickly, are easy to update, accessible to all, work on all browsers and can be quickly adapted to different media, this comprehensive guide represen......一起来看看 《HTML Dog》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具