分享

python提醒事件

 明灭的烟头 2021-04-24

定时任务是业务中很常见的一个需求。本文作者通过某公众号任务提醒的项目,介绍了如何实现用户定时提醒。

文 | 喵叔

原文:https://blog./post/how-wecron-schedules/

WeCron(微定时)是我开发的一个微信上的定时提醒机器人,它能解析用户输入的语音或者文字,提取其中的时间和事件信息,然后为用户设置提醒。这个服务上线后,经常有用户问我这里定时提醒的实现,因此这篇文章我就打算来谈谈WeCron是怎么实现这个功能的,希望大家以后设计定时调度类系统时能多一个参考。

通过微信设置定时提醒架构

下面是定时提醒部分的架构图:

WeCron定时功能架构图

整个流程还是比较简单的:用户输入一条提醒语音后, parser会把其中的时间和事件信息解析出来,存到数据库中;

同时,定时调度器会被触发,它到数据库中找到一个最近的提醒,计算出到当前时间的时间差,然后sleep相应的秒数;

过段时间,调度器醒来,它会将最近一段时间要发送的提醒任务提交到一个队列里面,由专门发送消息的worker向用户推送消息。这里使用队列的目的,一方面是消峰,另一方面是为了让发送消息的worker能够横向扩展。定时调度器

定时提醒类系统有一个特点,就是它的峰值特别明显。用户设置的提醒大多会集中在整点时间触发,尤其是早晨8、9点。面对这样一个不均衡的分布,固定时间轮训的调度法就显得有些naïïve,它很难在运行效率和提醒的及时性中找到一个平衡点。因此,WeCron中定时调度器被设计为一个事件循环,它能响应两种事件:数据库有更新或者插入操作

上一次设置的休眠时间到了

每当这个调度器被唤醒,它会首先检查有没有提醒要发送,然后再找到最近一个将要触发的提醒,休眠相应的时间。下面是一个简短的实现:remind_event = threading.Event()

defevent_loop():

whileTrue:

wait_seconds = process_jobs()

# This event wakes up on timeout or someone else sets it

remind_event.wait(wait_seconds)

defon_remind_update():

# This will wake up the remind_event

remind_event.set()

defprocess_jobs():

# Send reminds

reminds = get_unfired_reminds_older_than_now()

send_notification(reminds)

# And get the most recent remind

next_remind = get_unfired_reminds_newer_than_now().limit(1)

return(next_remind.notify_time - now).seconds

另外,为了提高提醒的及时性,这里的调度器会被启动好几份。这时面临的一个问题就是同一个提醒可能会被多个调度器调度到,用户也就有可能重复收到提醒。所以WeCron在选择提醒项的时候使用了select...forupdate语句,利用(行)锁来同步多个调度器。结束

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多