Cron Job

这是为Food tech family 实现的定时任务框架

背景

一句废话: 我们总是需要一个cron job框架的.

具体的业务场景有两种

  1. 每天晚上8点从数据dump生成一份报表给offline. 通常的做法就是使用 https://github.com/robfig/cron这种静态的库, 通过提前写好代码, 到时间了就执行.
  2. offline指定某一天某一刻执行一个东西, 比方说, 下个周一将数据库里的商家A关店. 这种情况下就不同通过提前写好来执行脚本, 必须要讲offline这种 需求 记录下来, 到时候在执行

难点

如果想要做的完美一点.还是有一些难点需要解决的

第一种需要解决的是

  1. 只有一个机器应该跑这个任务, 通过redis锁, 分布式锁解决
  2. 机器挂了, 重启了, 其他人应该启动起来接着跑

第二种需要解决的是

  1. 接受用户动态输入, 然后存在一个地方, 存一次不丢不漏 --- 简单,http调用就行
  2. 从存的地方取的时候, 多台机器只有一个能取的到, 然后执行. 如果成功其他人就不能再取了, 如果自己或者其他人应该重试

动态定时任务实现

  1. 使用redis+lua脚本, redis中采用sortSet, 执行时间作为sortKey, 然后因为单进程的lua脚本可以保证同时只有一个解释器在执行, 值得注意的是, 为了保证不多发, lua脚本会在拿到值之后删掉对应的数据, 这样其他人就拿不到了. 这样做的一个问题是一旦lua脚本返回, 之后执行失败, 也没有机会重试了.
  2. 使用DynamoDB(mysql) + lambda. 让Lambda每隔一段时间启动一下, 然后query DynamoDB. lambda可以通过回调的方式, 调用任意语言的handler.

DynamoDB + Lambda 模式的细节

无疑lambda是适合这种业务场景的. 稳定高效, 不用维护, 还便宜. 不过这里面有一些细节需要考虑

  1. 参数传递都是通过DynamoDB, 业务方往DynamoDB push任务的时候就要把callback写出来
  2. 核心的lambda读到DynamoDB的任务之后是要自己处理还是怎么搞?
    1. 如果每1min执行一个lambda, 而上一个 lambda 还没有执行完毕, 这样就有可能两个lambda都读到了同一个东西
    2. 如果核心的lambda只负责读取分发, callback每次都启动单独的lambda去调用就可以实现并发.
  3. 删不删?
    1. 删, 则是最多一次的实现
    2. 不删, 至少一次的不完美实现 (还是存在因为执行的慢, 多次获取的问题, 除了控制间隔,也没什么好办法. 难道要锁住lambda 一个启动了另外一个不启动?, 倒是有限制并发数为1的方法)