如何优化Vercel上超时的CRON Job?解决504网关超时问题
优化Vercel Cron Job避免504超时的解决方案
核心优化思路
针对Vercel无服务器函数10秒超时限制,从减少重复开销、并行处理、查询优化、快速响应四个方向优化代码:
- 复用Twilio客户端,避免循环内重复初始化
- 并行发送短信,替代串行循环缩短总耗时
- 修正日期查询逻辑,配合索引提升数据库查询速度
- 尽早返回响应,避免函数因等待全量操作完成超时
优化后代码
import dbconnection from "@/lib/dbconn"; import Birthday from "@/models/Birthday"; import twilio from "twilio"; // 全局初始化Twilio客户端,避免循环内重复创建 const twilioClient = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN); // 确保数据库连接仅初始化一次(需保证@/lib/dbconn为单例实现) dbconnection(); export default async function handler(req, res) { try { // 精准匹配当日生日:构造当日0点到次日0点的时间范围,避免时分秒干扰 const today = new Date(); const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate()); const endOfDay = new Date(startOfDay); endOfDay.setDate(endOfDay.getDate() + 1); // 使用lean()返回纯JSON对象,跳过Mongoose文档转换开销 const birthdays = await Birthday.find({ date: { $gte: startOfDay, $lt: endOfDay } }).lean(); if (birthdays.length === 0) { console.log("今日无生日记录"); return res.status(200).json({ success: true, message: "今日无生日记录" }); } // 并行处理所有短信发送请求,大幅缩短总耗时 const sendTasks = birthdays.map(async (birthday) => { try { const message = await twilioClient.messages.create({ messagingServiceSid: 'MG19c8d8f851ee2e2525446fc35d1667ab', body: `Subramanya, Today is ${birthday.name}'s Birthday!. Don't Forget to wish🎉`, from: process.env.TWILIO_PHONE_NUMBER, to: process.env.MY_NUMBER, }); console.log(`已发送生日提醒:${birthday.name} | SID: ${message.sid}`); return { success: true, name: birthday.name }; } catch (err) { console.error(`发送失败:${birthday.name}`, err.message); return { success: false, name: birthday.name, error: err.message }; } }); // 用Promise.allSettled确保所有发送任务执行完成,单个失败不影响全局 await Promise.allSettled(sendTasks); // 尽早返回响应,告知Vercel函数执行完成 res.status(200).json({ success: true, total: birthdays.length }); } catch (error) { console.error("Cron任务执行失败:", error); res.status(500).json({ success: false, error: error.message }); } }
额外优化建议
- 为日期字段添加索引
在Birthday模型中为date字段创建索引,提升查询效率:
// @/models/Birthday.js BirthdaySchema.index({ date: 1 });
- 确保数据库连接为单例
修改@/lib/dbconn实现单例连接,避免每次请求重复连接数据库:
// @/lib/dbconn.js import mongoose from "mongoose"; let isConnected = false; export default async function dbconnection() { if (isConnected) return; try { await mongoose.connect(process.env.MONGODB_URI); isConnected = true; console.log("数据库连接成功"); } catch (error) { throw new Error("数据库连接失败"); } }
- Pro版Vercel可调整超时配置
如果使用Vercel Pro计划,可在vercel.json中延长函数超时(最大60秒):
{ "functions": { "pages/api/cron.js": { "maxDuration": 60 } } }
内容的提问来源于stack exchange,提问作者Subramanya M Rao
相关产品推荐
相关产品推荐

