内容简介:计划任务一般都喜欢使用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事件,但对于处理几分钟或几秒或更短时间的系统,这是不可行的。幸运的是,对于 程序员 而言,在大多数企业中,“立即”一词意味着“在工作日结束时”,或“在本周末”,或“在事情发生的月份之后的季度结束之前” 。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 解耦并不难:分布式系统中的解耦
- 分布式系统中解耦的模式:胖事件 - mathiasverraes
- 分布式系统中的解耦模式:领域查询 - mathiasverraes
- 分布式系统中的解耦模式:概要事件 - mathiasverraes
- 分布式系统中的解耦模式:隔离事件层 - mathiasverraes
- 分布式系统中的解耦模式:完整性保证 - mathiasverraes
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
随机密码生成器
多种字符组合密码
HEX HSV 转换工具
HEX HSV 互换工具