Access denied, Please sign in and make sure you have proper permission.
业务要求:
用户出价竞拍产品,
比如 用户 1 竞拍产品 A,开始 6 个小时倒计时。6 个小时过去之后那么用户 1 就获得了产品 A。
用户 2 用户 3 也可以竞拍,新竞拍会重新开始 6 小时倒计时。
举例:
用户 1 花了 100 元竞拍产品 A,6 小时倒计时开始,
在剩下 5 小时(或任何其他时间)的时候,用户 2 花了 150 元竞拍产品 A,倒计时重置 6 小时。
6 小时过后用户 2 获得产品(因为期间没有其他人出价来重置倒计时了)
发文前的功课:
这些讨论多以周期任务为主。一次性任务讨论不多。
问题:
用 sidekiq perform_in 做这种一次性任务是个好的解决方案吗?是否有更方便更可靠的方案?
(perform_in 的文档地址: https://github.com/mperham/sidekiq/wiki/Scheduled-Jobs)
时间到了之后就触发一些代码:发邮件通知。修改 record 状态。等
有个简单的方案:
功能有这几个重点:
- 竞拍,更新状态 (价格/截止时间等)
- 到点后自动结束竞拍
有两个对象:(名字随意取的)
- 被竞拍物 (Goods)
- 竞拍物状态 (GoodsStatus)
每次有人出更高的价格,其实就是在更新 GoodsStatus,可以为每次出价都持久化一条数据,核心字段是价格
和截止时间
和竞拍人
,并将 Goods 对应到最新的 GoodsStatus。
每次竞拍都往 sidekiq 中插入一条定时任务,任务执行时检查当前 GoodsStatus 是否是最新的,不是的话直接退出。如果是最新的话就结束竞拍。
用 sidekiq 的时候需要注意的是,sidekiq 取定时任务的时间点并不精准,可能会有数秒的误差 (可以配置),sidekiq 里面的任务本质上是一个个被取出处理的,要保证 sidekiq 的处理能力足够强,避免当竞拍任务过多时,任务延迟过多。
竞拍应该还有个大盘,大盘在”轮询“的时候,也可以检查时间点,做结束竞拍的动作。
直觉上可以。
如果非要精确到秒或者毫秒的话,那就需要仔细控制 Worker 的执行时间,比如提前个几秒钟开始执行,然后在 Worker 本体内做精确的时间控制。
用户竞拍的时候,更改 product.current_bidder 用 lock_version,避免多人同时竞拍,每次 after_commit 后 更新 新的竞拍结束时间。
建议 cronjob 查询竞拍结束时间来确认 product 归谁。
因为
- Sidekiq API 并不一定是实时的结果,perform_in 也不一定是准时的
2.你忽略了并发的情况。
cronjob 你可以用一个死循环去检查 product 时间更精准一点,查询到了后要 lock,你可以用 sidekiq scheduler,设置一个 cron job 每过 5 分钟去执行一个检查任务,检查任务里不停地 while sleep,超过 5 分钟了自动结束。
非常感谢详细的回复~
lock_version 没懂是什么我去查查
perform_in 在用户量不大的时候,可能没啥问题,但是由于商品竞拍这种性质,火热商品有可能在一段时间内造成大量的竞拍事件,这样大量的事件堆积在 sidekiq 队列中,终究不是啥好事情,很有可能会影响整个 sidekiq job 的响应时间。即使有逻辑从队列中祛除已经无用的 perform_in,也是一个很繁琐的事情,频繁操作,也会导致各种一致性和响应速度的问题。
为啥不换个想法?为什么每一次竞拍都需要 perform_in?从你的需求上能了解到,你关心的只是这个商品最后的竞拍人,和这个竞拍人竞拍的商品的过期时间。
所以很简单,只要有一个周期性的 Job,统一处理这些已经过期的商品,并生成对应的处理 job。没过期的就让他继续 active,在竞拍时候做个判断,是否是已经到了到期时间,顺便在前端展示时候,给个过期提示之类的。
这样就可以保证,每次生成的 job 一定是可用的,而且不会产生冗余的事件。
就想 #9 说的那样,用一个 job 轮询查有哪些商品到期了,这样有一个 job 做检查就可以了。时间间隔看需求来定。可能要看下对列怎么处理 repeat job 的,假设时间间隔是 200 毫秒。第一个 200 毫秒到了,处理时间,但花了 200 毫秒,还没处理完,那这个时候,是同时做处理,还是说等第一个处理完,然后再做第二个。如果是处理完第一个,再处理第二个,假设第一个花了 405 毫秒,那是马上做第二个处理,还是说,要等第 600 毫秒才处理(这样的话就有延迟,js repeat 是这么处理的)。
应该有两类 job,一类 job 做检查到期,一类 job 做后续操作,至少要用两个独立的 job queue,两者不能相互影响(第二类 job 跑满 cpu 的时候,第一类 job 要能正常工作),优先级应该能解决,但最好还是测一下。