需求场景

当前有这样一个模块,用户A(被服务者)发布一个服务到平台,服务包含服务内容以及服务的开始和结束时间,用户B(服务者)可以选择预约用户A发布的服务
服务在被预约后会生成一个订单,用户B需要在服务开始时间到达时开始对用户A提供服务,并上传服务过程(手机拍照)
用户B在服务时间结束前完成全部服务过程的上传,用户A,用户B进行订单互评
流程结束

其中有4个时间节点需要系统自动处理:

  1. 距离服务开始前x(系统配置)分钟时,系统需要主动向用户B推送服务即将开始的通知
  2. 服务开始时间到达时,系统需要自动开始服务(更新订单状态为:服务中)
  3. 服务结束时间到达时,系统需要根据当前服务流程上传情况自动更新当前服务订单状态为:已完成/超时取消
  4. 对于已完成未评价的服务订单,系统需要在到达x(系统配置)小时后自动评价订单

解决方案

系统定时任务

最初使用了laravel自带的Task Scheduling处理以上流程,但是问题也不少:

  1. 由于需要批量查询,批量更新,后期数据量到达一定量级的时候mysql性能必然会受到较大影响
  2. 项目中对列表数据,详情数据几乎都使用了缓存,而缓存更新机制也是写在了laravel框架model层的events事件中,但是模型事件无法通过批量操作时触发(官网文档), 因此只能手动更新缓存

    When issuing a mass update via Eloquent, the saved and updated model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update.

  3. 时间粒度只能精确到分钟

延时队列

针对上述问题,我决定把这几个系统自动执行流程通过基于queues#delayed-dispatching重写(底层通过zset实现)

基本流程:

  1. 用户预约服务时将服务订单分发到两个队列(延时时间根据订单开始时间距离当前时间的差值决定[单位:s]):服务即将开始的通知队列,服务自动开始队列
  2. 服务开始时将订单分发到超时自动结束队列(延时时间根据订单结束时间距离当前时间的差值决定[单位:s])
  3. 服务完成时将订单分发到超时未评价自动评价队列(延时时间根据系统配置订单完成后允许最长等待评价时间决定[单位:s])

至此,通过延时队列解决了定时任务带来的问题