如何检测Socket.io emit是否成功?避免消息仅入库未推送
确保WebSocket消息推送与数据库写入的一致性
我正在开发一款消息交互系统,需要确保用户发送的消息已通过WebSocket成功发送,避免出现消息存入数据库但未通过Socket推送的情况。
当前代码实现
发送Socket消息及数据库创建消息的代码:
socket.emit("send-msg", { content, friendsId, userId, receiverId, }); const message = prisma.message.create({ data: { content, friendsId, userId, }, });
核心推送逻辑代码:
if (receiverUser !== undefined) { io.to(receiverUser.socketId).emit("msg-recieve", { userId, friendsId, content, }); }
解决方案
1. 利用Socket.io的确认回调保证顺序
通过emit的回调参数,确认推送成功后再执行数据库写入,从根源避免不一致:
// 客户端/发送端代码 socket.emit("send-msg", { content, friendsId, userId, receiverId, }, (ackResult) => { if (ackResult.success) { // 推送成功后写入数据库 await prisma.message.create({ data: { content, friendsId, userId, }, }); } else { // 推送失败,提示用户或重试 console.error("消息推送失败,未保存到数据库"); } }); // 服务器端监听send-msg事件 socket.on("send-msg", (data, callback) => { let isPushSuccess = false; if (receiverUser !== undefined) { io.to(receiverUser.socketId).emit("msg-recieve", { userId: data.userId, friendsId: data.friendsId, content: data.content, }); isPushSuccess = true; } // 返回确认结果给发送端 callback({ success: isPushSuccess }); });
2. 事务+状态标记+重试机制(适合需先存库的场景)
如果业务要求必须先写入数据库,可通过状态标记和定时重试来补推:
- 写入数据库时,给消息添加
status字段,初始值为pending(待推送) - 执行Socket推送,成功后更新
status为sent(已推送) - 编写定时任务,扫描
status=pending的消息,重新执行推送逻辑,最多重试N次后标记为failed(推送失败)
3. 添加推送日志便于排查
记录每条消息的推送详情,方便定位问题:
// 推送完成后记录日志 await prisma.pushLog.create({ data: { messageId: message.id, receiverId: data.receiverId, status: isPushSuccess ? "SUCCESS" : "FAILED", pushTime: new Date(), failureReason: isPushSuccess ? null : "接收方Socket未在线" }, });
内容的提问来源于stack exchange,提问作者Rafael
相关产品推荐
相关产品推荐

