如果用定时任务设置一个每秒执行的脚本,那样可能影响服务器性能。
1
Azmeont 2017-10-13 16:17:18 +08:00
查询订单状态时检查是否超时
|
2
hging 2017-10-13 16:18:25 +08:00 1
创建订单的时候 创建一个 30 分钟后执行的异步任务 如果支付成功取消这个任务 如果没有支付 就会自动执行。
|
3
whileFalse 2017-10-13 16:19:10 +08:00
定时任务每分钟呢?
|
4
reus 2017-10-13 16:22:25 +08:00
怎么影响性能?
|
5
WuwuGin 2017-10-13 16:23:41 +08:00 via Android
提出一个推测的建议:因为最早之前 steam 上支付卡单,支付后显示 pending。最终都是整点到库(听说是 union pay 的锅)。所以我感觉都是整点检测吧,或者定一个时间段。
|
6
herozw OP @whileFalse 因为倒计时是按每秒计算。
|
8
Felldeadbird 2017-10-13 16:29:22 +08:00
1.cron
2.用户进入订单或者后台客服进行订单操作时进行过期处理。 不要担心服务器性能。服务器性能是用来消耗的。 |
9
wangxn 2017-10-13 16:29:25 +08:00 via Android
不用定时啊,只要客户重新查看这个订单,假如超时了,那么就做相应处理,假如一年都不访问,那就一直保持未超时的状态。
|
10
Millyn 2017-10-13 16:29:50 +08:00 1
生成订单时就创建一个过期时间的字段,根据这个字段来判断是否过期。
|
11
kaka826 2017-10-13 16:30:03 +08:00 2
用 redis 被动过期,客户端查询订单就从 redis 里取判断,redis 里的 key 过期,就取消订单
|
12
holystrike 2017-10-13 16:30:38 +08:00
首先取消时业务逻辑做好判断
然后另外有个轮询取消任务就可以了 |
13
domty 2017-10-13 16:31:00 +08:00
做过类似的。
做个队列一个个按时间丢进去进行,然后开个定时器每隔一段时间从队列头部拿出来一个检查是否到时间,倒了就拿出来改状态更新到数据库。 检查前先去库里检查是否到手动被取消,若已被取消从队列头推出。 |
14
hinate 2017-10-13 16:31:07 +08:00
设计一个任务中心,使用延时任务。
|
15
b821025551b 2017-10-13 16:31:10 +08:00
要留记录就定时每秒执行,不留记录直接 30 分钟的缓存
|
16
justfindu 2017-10-13 16:35:15 +08:00
每分钟执行就可以了 反正都是取消订单, 你还在乎时间延时么. 即使最后一秒他付款了, 那不就是目的么 , 而且退款流程加入队列
|
18
chairuosen 2017-10-13 16:40:44 +08:00 1
记得微信高可用公众号分享过一个类似文章。
1,每个商品一个定时器还是全局一个定时器。每个商品一个的话,太耗性能。所以全局一个。 2,全局一个定时器怎么知道谁到了时间谁没到。遍历一遍页耗性能。 方案是如果倒计时 30 分钟,精确到 1 分钟,就建 30 个队列,有个游标,1 分钟换下一个队列,新插的放这个队列,然后失效再下一个队列并清空。 |
19
qiujin 2017-10-13 16:42:01 +08:00
使用 beanstalkd 这种有延迟任务功能的队列
|
20
lepig 2017-10-13 16:48:31 +08:00
|
22
imn1 2017-10-13 16:49:50 +08:00
如果不需要推送通知的话,有必要搞定时器么?
判定时间状态不允许操作就是了 |
23
zhea55 2017-10-13 16:52:31 +08:00 1
Redis 里面有个 expire 的功能,时间到期了,会删除对应的 key
google:redis expire callback 貌似过期了可以得到通知。 性能问题,第三方去考虑。 |
25
tagtag 2017-10-13 16:53:31 +08:00
被动的超时处理应该没什么疑问,主动的应该只能轮询了吧。
|
26
gamexg 2017-10-13 17:03:01 +08:00 via Android
订单本身有超时时间字段,需要关注超时时设置这个字段。
每次客户查看订单时检查下是否超时来显示订单状态。 另外后台有个每分钟或更长时间的定时任务处理超时订单,直接查数据库,这个任务主要负责回滚库存或发邮件通知等操作。 除非很大的量,不然太建议过早优化上队列之类的。 即使上专门的队列也需要一个直接查数据库的兜底机制来防止队列丢失数据或执行错误等造成超时订单长时间未处理。 |
27
qq316107934 2017-10-13 17:08:08 +08:00 via Android
大家都不考虑订单超时之后商品回库的问题吗?感觉还是要用定时器啊
|
28
Patrick95 2017-10-13 17:10:58 +08:00
对啊楼上好多人提出的解决方案都没有考虑过订单支付超时商品回库的问题。
|
29
cowpea 2017-10-13 17:11:23 +08:00
@whileFalse 我也觉得分钟就行了,没有观测者的话,差个几十秒也没啥(业务特别严谨就另说,再说回来,能被超时取消的单子,用户也不会在乎那几十秒,右侧取整分肯定会多几十秒)。有观测的话,判断超时做处理就好了。
|
30
linxl 2017-10-13 17:13:37 +08:00
redis.
每秒都去查询 redis 总不会有啥问题了吧. |
31
linpf 2017-10-13 17:16:19 +08:00
我是做了定时任务,同时每次访问该数据的时候也判断一下。
|
32
lilixiang999 2017-10-13 17:21:36 +08:00
python 的话 celery 有一个 countdown 的功能很合适,也能精确到订单维度,在处理 task 的时候订单支付超时 然后商品回库等一系列操作
|
33
UnPace 2017-10-13 17:24:07 +08:00
用户主动触发改变订单状态肯定不可行,最合理的就是定时任务扫。
|
34
ixixixe2 2017-10-13 17:25:16 +08:00
@qq316107934 搞个 0 点自动检测不就好了
|
35
cxbig 2017-10-13 17:30:52 +08:00
Cronjob 每分钟跑一次可以了
|
36
gcli 2017-10-13 17:32:54 +08:00
定时任务,每分钟执行一次,超时的订单,更改订单状态,释放资源
|
37
orderc 2017-10-13 17:36:50 +08:00
google 延迟队列
|
38
dullwit 2017-10-13 17:42:09 +08:00
DelayQueue,支持延时获取元素的无界阻塞队列
|
39
gcli 2017-10-13 17:46:06 +08:00
好吧,涨知识了,延迟队列
接下来准备把定时任务替换为延迟队列 |
40
minotaur 2017-10-13 17:46:35 +08:00
延迟消息队列 简单点就 redis
|
41
upupxjg 2017-10-13 17:53:02 +08:00
记录创建时间,再次操作的时候检查超时,超时了有后续处理的话(比较麻烦的情况)设置状态+进队列,怕太多再搞个定期 dump 归档之类的
|
42
upupxjg 2017-10-13 17:54:24 +08:00
“最优解”要看你超时了有什么业务什么处理
|
43
honeycomb 2017-10-13 17:57:03 +08:00 via Android
guava 里有一个 cache,可以参考它的原理。
|
44
ipconfiger 2017-10-13 18:02:17 +08:00
首先你的订单在失效的时候需要有两个状态 一个是 失效 另外一个是完成失效, 失效可以用失效时间在记录中提现, 小于当前时间的都是属于失效, 然后在后台任务中慢慢处理失效的订单的其他回退的操作, 比如退款, 库存之类的, 都处理完后再设置状态为完成失效.
|
45
frazy 2017-10-13 18:05:16 +08:00
延迟 ( dead )队列 + Job 补充 解决问题
|
46
zjqzxc 2017-10-13 18:20:30 +08:00
前后台分别进行
前台 js 负责倒计时,倒计时结束后向后台发送一个倒计时结束的请求,此时后台检查是否确实已经超时了 后台把这个计时加入延迟队列,采用 redis 的话就把检查实际间隔设置断些,几秒几十秒;磁盘数据库的话就 1~2 分钟甚至 3~5 分钟都可以。 |
47
twogoods 2017-10-13 18:22:50 +08:00
|
48
movistar 2017-10-13 18:34:56 +08:00
有的解决方案能解决问题,有的就是小玩具
这种东西肯定得依赖中间件的,不管是分布式存储,分布式消息队列还是分布式锁 难道一个商城只有一台服务器一个服务么...... 就算最简单的每秒扫一次库更新状态,N 台服务器之间怎么分配任务... 这些都是线上产品需要解决的问题 玩具无视,单机就太简单了...... |
49
orderc 2017-10-13 18:37:43 +08:00
|
50
orvice 2017-10-13 18:39:18 +08:00 2
不知道大家有没有注意到
cloudxns 每次登陆,有时候能收到一些域名取消托管的邮件。 所以,你可以用户进行某些操作后,去触发一些任务。 |
51
liteyou 2017-10-13 18:42:49 +08:00 via Android
定时任务总还是蛮担心的,一旦启动,就像是开闸放出来的猛兽。要么出现队列任务卡住的情况,本该清理的数据堆积如山,;要么干了不该干的事情。总之,完全无人值守的任务,还是定期去喵一眼,比较放心(❁´ω`❁)
|
52
petelin 2017-10-13 19:13:53 +08:00 1
我的高可靠性解决方案:
创建订单之后, 写到延迟队列里一个任务, 同时记录数据库, 失效时间 兜底轮训, 每一分钟轮训一遍数据库, 根据订单状况+失效时间, 这两个字段加个索引, 如果觉得处于代付款的订单不多的话,可以加在订单状态上. 成功之后, 改订单状况. 对于我们的业务是够了, 30 分钟能有多少个未付款的订单 ?? k 级别的轮训一遍小事呀~ |
53
bobuick 2017-10-13 19:16:39 +08:00
python 的话,celery 可以做到。以前做电商做过类似的,可以用 celery 配合 rabbitmq 做成延迟队列的形式。
不过目前市面上也有不少延迟队列服务,可直接使用 |
54
refear99 2017-10-13 19:29:36 +08:00
创建订单的时候就插入延迟队列,设置 30 分钟延迟
worker 长轮训这个队列,30 分钟自动可见,消费的时候开启事务锁订单,检查是否已支付,如果未支付就关单退优惠券,已支付的话就删除消息 |
55
fortunezhang 2017-10-13 20:31:26 +08:00
@wangxn 一般我也是这么做,等他查询的时候更改状态。但是自从有了微信模板消息,就 tm 不好用了。客户说 30 分钟没付款,你给他发个模板消息,这就尴尬了
|
56
wangxiaoer 2017-10-14 09:16:08 +08:00 via Android
@hging 我觉得这种方式成本高,你需要考虑异步任务执行意外的情况,比如异常中止怎么办,重启服务器怎么办等,如果考虑异步任务恢复就要面临集群,调度等。
|
57
killerv 2017-10-14 10:25:33 +08:00
这个不用走队列吧,只需要在操作订单相关的时候对比一下时间就行了吧
|
58
jsrgqinbin 2017-10-14 10:35:26 +08:00
延迟队列
扫描太耗性能了 |
59
sweelia 2017-10-14 11:00:01 +08:00 via Android
rabbitmq 延时队列,定时任务扫全库扑杀漏网之鱼
|
60
Reign 2017-10-14 11:29:25 +08:00 via iPhone
楼上又是 crontab 又是队列的真是服了你们了,至于这么复杂么?生成订单写一个时间戳和 ID,下次用户再访问“我的订单”时取消这个超时的订单就行了,如果用户再也不访问这个订单了,你还关心这个 ID 搞毛线啊?
|
63
SlipStupig 2017-10-14 14:10:08 +08:00
https://github.com/ouqiang/delay-queue, 完全符合楼主要求...
|
65
zhx1991 2017-10-14 17:57:39 +08:00
定时任务啊
这种基础组件应该有做一个吧. |
67
runningman 2017-10-15 11:15:57 +08:00
@SlipStupig 这个确实符合,但是这个是 go 写的,有 php 写的没,
|
68
0915240 2017-10-15 11:20:01 +08:00
@Reign #64 给钱了没货了怎么办,大家都来订单你都说好好好给钱就发货,然后你没那么多货,不就 gg 了。有一个商品下单商品占位的过程。
|
70
Winny 2017-10-16 08:53:49 +08:00
1.订单表增加过期时间字段,用在查询页面展示并在用户试图操作的时候拒绝(同时触发回库逻辑)
2.同时跑一个固定间隔的计划任务,每隔一段时间(根据业务和负载决定),将订单表中的过期记录关闭(避免 1 没有触发导致回库的问题) |
71
mingyun 2018-01-21 11:13:45 +08:00
延迟队列 +1
|
72
go_starter 2019-05-07 17:46:22 +08:00
不用轮训的方式如何实现?轮训比较消耗服务器资源,如果订单量不多还好说,电商这种订单很大的情况不会采用轮训的方法的。初步想法是在订单提交后注册一个异步任务,比如 30 分钟后执行。如果订单状态是未支付,就取消订单。如果已支付,啥都不用做。最后删除任务。至于任务的中断、异常、恢复、持久化等,需要任务系统做好服务的 QOS 即可。
|
73
huangke 2019-06-03 16:29:44 +08:00
生成订单的时候把订单号存入 Redis 作为 key,按订单有效时间设置失效时间,当监听到键失效的时候就可以执行代码将订单标记为过期,关键词:notify-keyspace-events
|