计划任务通常都喜欢使用Cron做业来完成,好比使用spring scheduler或Quartz,本模式推荐使用黑盒式的不可知事件替代Cron做业。程序员
许多业务流程涉及须要在未来执行的某些操做或工做或工做负载。它能够是一次性动做或重复动做,能够安排在特定日期(例如圣诞节),重复日期(月的最后一个工做日)或超时(从如今起30天)。spring
咱们但愿保持整个流程的领域逻辑在单个(微)服务中很好地隔离,所以这也是此操做的逻辑所在。可是有一小部分逻辑不在这项服务中:就是事实执行须要进行,以及什么时候须要进行。数据库
Cron是最麻烦的:它只适用于重复操做,而且外部工具几乎不能控制。在大型系统中,cron文件可能形成巨大的混乱。更现代的解决方案容许咱们经过在代码中调用API来安排使用,这样可将逻辑移动到咱们本身的服务中。但从根本上说,调度程序仍然是一个单独的服务,可是它涉及到知识比它应该知道的会更多。使用DDD术语,咱们业务流程的无所不在的语言在此服务中泄漏。咱们的系统中必须有更多类型的元素和更多的可移动部件。bash
思惟转换是:将时间流逝视为另外一个领域事件,就像全部其余事件同样。毕竟,若是咱们将领域事件定义为与业务相关的事件的粒度时间点,好比下一个工做日,月或季度。并发
在新的设计中,cron或调度程序会按期发出普通的时间段事件,例如DayHasPassed {date}午夜事件或一个 QuarterHasPassed {year, quarter}。全部感兴趣的服务都会收听此事件。他们能够经过执行操做,增长计数器,或经过查询某个数据库并按日期过滤来对其作出反应,以查找有一些工做要作的项目。工具
时间管理着一切,有用的示例:可计费小时,订阅,资源使用,租赁,累积利息,付款,报告,工资,维护计划以及全部循环。测试
在发票到期日,咱们须要向客户发送提醒。在旧设计中,咱们能够设置一个调用的cron做业CheckForOverdueInvoices;在新设计中,cron DayHasPassed每隔午夜就产生一次,在InvoiceDebtCollection中监听DayHasPassed。ui
每当此事件到达时,InvoiceDebtCollection查询SELECT * FROM Invoice AS i WHERE DATEDIFF(i.dueDate, NOW()) >= 30。它能够直接发送提醒,但更好的方法是发出新InvoiceBecameOverdue事件。spa
如今,该服务能够收听本身的事件并发送提醒。其余服务也能够对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事件,但对于处理几分钟或几秒或更短期的系统,这是不可行的。幸运的是,对于程序员而言,在大多数企业中,“当即”一词意味着“在工做日结束时”,或“在本周末”,或“在事情发生的月份以后的季度结束以前” 。