Node.js服务端定时调度实现过期投注订单通知方案咨询
服务端定时处理过期投注订单的实现方案
你当前使用客户端Ajax+setInterval的方案确实存在明显缺陷:用户关闭页面后定时任务直接终止,无法保证通知触达,同时多用户同时轮询会产生大量无效请求,额外增加服务端压力。结合你的技术栈和30分钟最短过期时长的场景,下面两个轻量方案实现简单、性能损耗极低,完全不会造成服务器过载:
方案1:Node.js层集成node-schedule库(实现成本最低,适合新手)
直接在你现有的Express项目中引入轻量定时任务库即可,不需要额外部署第三方服务,学习成本极低。
- 安装依赖:
npm install node-schedule
- 核心实现逻辑:
设置每10分钟执行1次定时任务(远小于30分钟的最短过期时长,不会出现漏单),每次只查询已过期且未发送通知的订单,处理完成后标记为已通知避免重复推送。 - 代码示例:
const schedule = require('node-schedule'); const { Pool } = require('pg'); // 初始化Postgres连接池,用你现有项目的配置即可 const pgPool = new Pool({ // your pg config }); // cron规则:分 时 日 月 周,*/10代表每10分钟执行一次 const expiredOrderJob = schedule.scheduleJob('*/10 * * * *', async () => { try { // 批量查询待通知的过期订单,加LIMIT避免单次处理量过大 const queryRes = await pgPool.query(` SELECT id, user_id, order_no FROM bet_orders WHERE expire_time < NOW() AND notification_sent = FALSE LIMIT 1000 `); const expiredOrders = queryRes.rows; // 遍历发送通知,通知逻辑用你现有业务的实现即可(站内信/短信/邮件等) for (const order of expiredOrders) { await sendUserNotification(order.user_id, `您的投注订单${order.order_no}已过期`); // 标记为已通知,避免重复发送 await pgPool.query(` UPDATE bet_orders SET notification_sent = TRUE WHERE id = $1 `, [order.id]); } } catch (err) { console.error('过期订单通知任务执行失败:', err); } });
- 注意事项:
该方案适合单实例部署的Express服务,新手阶段单实例完全可以满足需求。如果后续扩展为多实例部署,只需加简单的分布式锁避免多个实例重复执行任务即可。
方案2:PostgreSQL自带pg_cron扩展(无需修改Node.js代码)
如果不想在Node层新增依赖,可以直接使用Postgres官方的定时任务扩展,任务直接在数据库层面执行,性能损耗更低。
- 首先开启扩展(大部分云托管Postgres实例默认支持直接开启):
CREATE EXTENSION IF NOT EXISTS pg_cron;
- 创建定时任务,示例为每10分钟执行一次批量标记过期订单,你可以配合业务逻辑给用户拉取通知即可:
SELECT cron.schedule( 'expired-order-notify', -- 任务名称 '*/10 * * * *', -- 执行频率:每10分钟 $$ UPDATE bet_orders SET notification_sent = TRUE WHERE expire_time < NOW() AND notification_sent = FALSE; $$ );
性能说明
两种方案的资源消耗都可以忽略不计:只要给bet_orders表的expire_time和notification_sent字段加联合索引,单次查询耗时基本在毫秒级,哪怕把执行频率调到每5分钟一次,也完全不会影响服务正常性能,比客户端轮询的资源消耗低两个数量级以上。
内容的提问来源于stack exchange,提问作者Calin89
相关产品推荐
相关产品推荐

