QStash:独立游戏工作室的异步任务神器,服务器不用排队
日期:2026-05-01 标签:QStash · 消息队列 · 异步任务 · 游戏后端 · 独立开发者
上一篇聊了 Upstash Redis——防崩溃的限流和缓存层。这一篇说说 Upstash 家的另一个工具:QStash。
它解决的问题很简单,但被大多数独立开发者忽视了:耗时操作不应该让玩家等待。
什么是异步任务,为什么游戏后端需要
你的玩家按下"导出存档",服务器要做几件事:
- 从数据库查出玩家所有存档数据
- 把数据打包成 ZIP 格式
- 上传到云存储
- 发邮件通知玩家"下载链接来了"
整个过程可能需要 3-10 秒。如果同步执行,玩家点了之后要盯着屏幕等 10 秒——在这 10 秒里,如果服务器还在处理其他请求,响应时间会更长,玩家体验极差。
更糟糕的:如果你的服务器限制了函数运行时间(大多数 Serverless 平台默认限制 10 秒),这个请求可能直接超时,存档导出失败,玩家不知道发生了什么。
异步任务的思路是:玩家发出请求 → 服务器立刻返回"已收到,处理中" → 后台慢慢做完整的工作 → 完成后主动通知玩家。
玩家的等待时间从 10 秒变成毫秒级。
QStash 是什么
QStash 是一个无服务器消息队列——你把任务投进队列,QStash 负责在适当的时候把任务发给你的处理接口,支持延迟执行、失败重试、任务调度。
它不是传统意义上的 RabbitMQ 或 Kafka,你不需要部署任何东西,不需要管连接,不需要写消费者代码——只需要一个能接收 HTTP 请求的接口,QStash 就能把任务推送过来。
三个核心能力:
| 能力 | 描述 | 游戏场景 |
|---|---|---|
| 消息投递 | 把任务发给指定 URL,失败自动重试 | 导出存档、发推送通知 |
| 延迟执行 | 设定多少秒/分钟后执行 | 游戏内计划事件、定时重置排行榜 |
| 定时调度 | Cron 表达式定期触发 | 每日签到奖励、每周清空临时数据 |
独立游戏工作室的真实场景
场景一:存档导出(不阻塞玩家)
玩家点"导出存档",不同步处理,直接入队:
import { Client } from "@upstash/qstash";
const qstash = new Client({ token: process.env.QSTASH_TOKEN });
// 玩家发请求时,立刻入队,立刻返回
export async function handleExportRequest(userId) {
await qstash.publishJSON({
url: "https://yourgame.com/api/process-export",
body: { userId },
retries: 3, // 失败自动重试 3 次
delay: 0, // 立刻执行
});
return { status: "queued", message: "正在处理,完成后将通知你" };
}
// 实际处理接口(由 QStash 回调)
export async function processExport(userId) {
const saves = await supabase.from("player_saves").select("*").eq("user_id", userId);
const zipBuffer = await createZip(saves.data);
const fileUrl = await uploadToStorage(zipBuffer, `export-${userId}.zip`);
await notifyPlayer(userId, fileUrl);
}
玩家点击 → 0.1 秒收到"处理中" → 后台 5 秒完成导出 → 推送通知到游戏客户端。
场景二:全服推送通知
游戏大版本更新,给 2 万玩家发更新通知。不能一次性发——服务器撑不住,也容易被邮件服务器判定为垃圾邮件。
QStash 的延迟投递可以把 2 万条通知分散在 5 分钟内发送:
const players = await supabase.from("players").select("id, email");
for (const { id, email } of players.data) {
await qstash.publishJSON({
url: "https://yourgame.com/api/send-notification",
body: { userId: id, email, version: "v2.0" },
delay: Math.floor(Math.random() * 300), // 5分钟内随机延迟
});
}
2 万条任务全部进队,QStash 按延迟时间均匀分发,每次只触发少量接口调用,邮件服务器也不会报警。
场景三:定时排行榜重置
每周一零点重置周排行榜,不需要写 Cron 服务器,QStash 直接支持 Cron 调度:
// 注册定时任务(一次配置,永久运行)
await qstash.schedules.create({
destination: "https://yourgame.com/api/reset-leaderboard",
cron: "0 0 * * 1", // 每周一 00:00 UTC
body: JSON.stringify({ scope: "weekly" }),
});
这个任务注册之后就不需要管了,QStash 每周一自动触发你的接口,接口挂了还会重试。
免费版额度够吗
QStash 免费版:每天 500 条消息,每月 1 万条。
对于早期独立游戏来说,1 万条/月是什么级别?
- 每天排行榜重置:30 条/月
- 每次版本更新推送(2 万玩家):2 万条/次,这种情况需要升级
- 日常存档导出请求(预估 50 个玩家/天):1500 条/月
正常运营期间,免费版够用。大版本更新推送是唯一可能超限的场景,那时候你的游戏也有收入了。升级到 Pro($20/月)可以无限消息。
与 Upstash Redis 配合使用
QStash 和 Upstash Redis 是同一公司出的,两者配合是最自然的方案:
- Redis 挡在前面:玩家请求先经过限流检查,防止有人刷导出接口
- QStash 在后面:通过限流的请求进入 QStash 队列,后台有序处理
- Supabase 收尾:处理结果存入 Supabase,Realtime 推送通知给玩家
三件套的任务分工清晰,没有功能重叠,也没有耦合依赖。你可以只用 QStash,也可以三件一起用,完全自由。
快速开始
第一步:登录 upstash.com → 进入控制台 → 找到 QStash → 复制 Token
第二步:在你的后端项目安装 SDK
npm install @upstash/qstash
第三步:把耗时操作从同步改为异步(参考上面的存档导出示例)
第四步:用 QStash 控制台的"Logs"面板监控任务执行情况,失败任务会列在这里,方便调试
整个接入过程大约需要 2-3 小时,主要时间花在拆分同步接口为异步接口上。
相关资源
- QStash 官方文档:https://docs.upstash.com/qstash
- QStash SDK(Node.js):https://github.com/upstash/sdk-qstash-ts
- 免费计划详情:https://upstash.com/pricing#qstash
- 上一篇:Upstash Redis:独立游戏工作室的防崩神器
- 下一篇:Serverless 三剑客合集