You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化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 });
  }
}

额外优化建议

  1. 为日期字段添加索引
    在Birthday模型中为date字段创建索引,提升查询效率:
// @/models/Birthday.js
BirthdaySchema.index({ date: 1 });
  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("数据库连接失败");
  }
}
  1. Pro版Vercel可调整超时配置
    如果使用Vercel Pro计划,可在vercel.json中延长函数超时(最大60秒):
{
  "functions": {
    "pages/api/cron.js": {
      "maxDuration": 60
    }
  }
}

内容的提问来源于stack exchange,提问作者Subramanya M Rao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:17:41