主题
Next.js 高级架构
Next.js 长耗时任务、后台任务和连接池如何治理?
请求处理函数不是天然的任务系统,长任务必须从页面请求中拆出,并根据运行时治理连接和重试。
面试官想考什么
- Route Handler 里能不能启动一个不 await 的后台任务? 考察平台生命周期。
- Serverless 如何避免数据库连接爆炸? 考察连接池。
- 长任务失败后怎么恢复? 考察队列和幂等。
- 页面如何展示任务进度? 考察异步 UX。
一句话回答
text
Next.js 请求函数只负责校验并创建 job,长任务交给有持久化状态和重试策略的队列/Worker;数据库连接按运行时采用池化或代理,任务和副作用用幂等键保护,页面通过查询、SSE 或 WebSocket 展示状态。面试回答详解
1. 请求与任务分离
text
POST /jobs -> validate/auth -> create job -> return 202 + jobId
worker -> execute -> checkpoint -> complete/fail
UI -> poll/subscribe -> render status不要依赖请求返回后进程仍然存活。Serverless 可能冻结或终止实例,Edge 也有 API 和时长限制。
2. 任务状态
至少区分 queued、running、retrying、succeeded、failed、cancelled、expired。状态转换要有版本或乐观锁,避免两个 worker 同时执行。
3. 重试与幂等
瞬时网络错误可退避重试,业务拒绝不能无限重试。每个 job 和外部副作用都有 idempotency key;重试前读取 checkpoint 或下游状态,避免重复写入。
4. 连接池策略
- Serverless:优先托管连接池、数据库代理或 HTTP 数据接口,限制并发。
- 长生命周期 Node:复用进程级连接池,但要处理热重载和优雅关闭。
- Edge:选择兼容 Edge 的网络访问方式,不假设原生 TCP 驱动可用。
连接数预算应按实例并发、区域数和最大扩容计算,而不是只看单机。
5. 页面体验和观测
创建 job 后立即返回状态页,支持刷新、取消、重试和下载结果。记录 queue wait、run time、attempt、worker、连接等待、失败原因和最终业务结果。
可直接背诵的 30 秒回答
text
长任务不能靠 Route Handler 返回后继续跑,我会先创建带幂等键的 job,返回 jobId,再由队列和 Worker 执行并持久化状态。数据库连接按 Serverless、Node、Edge 分别选择连接池、代理或兼容驱动。前端用轮询或流订阅展示 queued/running/succeeded/failed,重试、取消和副作用都要可恢复。扩展知识
轮询与推送
- 轮询:实现简单、适合低频状态和跨网络环境。
- SSE/WebSocket:实时性好,但连接、重连、代理和扩缩容更复杂。
- 两者都应以持久化 job 状态为权威来源。
面试官追问链
追问一:void runTask() 为什么不可靠?
- 考察点:运行时生命周期。
- 回答方向:平台可能在响应后冻结或终止实例,异常也无法可靠重试;应交给持久化队列。
追问二:任务取消如何做到?
- 考察点:协作式取消。
- 回答方向:写入 cancel_requested,worker 在阶段边界检查 signal,无法立即终止时仍要标记最终状态并停止后续副作用。
追问三:队列重复投递会怎样?
- 考察点:至少一次语义。
- 回答方向:worker 幂等消费,使用 job attempt、锁/租约、checkpoint 和外部副作用幂等。