AppEngine 推送队列允许安排任务以供将来执行(如果添加了该TaskOptions.etaMillis(...)
选项)。此方法需要一个long
参数,该参数以绝对毫秒为单位指定执行任务的时间,正如System.currentTimeMillis()
.
鉴于 AppEngine 不保证服务器时钟同步,并且时钟可能会以 HOURS 的顺序关闭!!!(请参阅0:36:07 的“Google I/O 2010 - 使用 Google App Engine 的数据管道”),这怎么可能可靠?
让我们考虑以下示例:
- 一个 http 请求进来并被路由到一个时钟恰好提前 30 分钟的实例
- 在请求处理期间,我想将一些批处理推迟到后台任务
- 我希望在大约 10 秒内将结果报告给用户
- 所以,我用 ETA 来安排任务
System.currentTimeMillis() + 10,000
- 考虑到 30 分钟的时钟偏差,这个 ETA 实际上对应于从现在开始的 30 分 10 秒
- 因此,如果任务现在由不同的实例处理,它可能会暂停超过 30 分钟
- 不用说,对于用户来说,我的服务似乎已经死了
这是否在底层 API 中以某种方式阻止?如果没有,Task ETA 怎么可能有用呢?是否必须将 ETA 指定为相对时间而不是绝对时间才能使其正常工作?
真正可悲的是,实际上有一个调用的函数TaskOptions.countdownMillis(...)
确实需要一个相对时间,但是查看
最终处理该值的源代码,可以看到它只是简单地转换为基于相同高度不可靠的绝对时间规范System.currentTimeMillis()
。
更糟糕的是:如果您不指定 ETA 或倒计时,此函数仅使用当前系统时间而不是 0,因此即使您希望立即执行的任务也可能最终会暂停一个小时或更长时间!
这是一些重大错误还是我错过了什么?
此外,这同样适用于Pull Queues中的 Tasks 租约,对吗?