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

Next 13 App目录下Vercel Cron Job触发后数据库无变更问题排查

问题:Vercel Cron Job触发后数据库无变更(本地正常)

我使用Next.js 13 App目录开发项目,拥有如下route.ts文件:
路径:

app/api/cron/set-completed-goals/route.ts

代码内容:

import { prisma } from '@/lib/prisma';
import { NextResponse } from 'next/server';
export async function GET() {
  const users = await prisma.user.findMany();

  for (const user of users) {
    const goals = await prisma.goal.findMany({
      where: { userId: user.id },
    });

    for (const goal of goals) {
      if (goal?.percentage ?? 0 >= 100) {
        await prisma.$transaction([
          prisma.user.update({
            where: { id: user.id },
            data: {
              completedGoals: [...user.completedGoals, goal.id],
            },
          }),
          prisma.goal.update({
            where: { id: goal.id },
            data: { percentage: 0 },
          }),
        ]);
      }
    }
  }
  return NextResponse.json({ message: 'Completed goals updated' });
}

同时配置了vercel.json:

{
  "crons": [
    {
      "path": "/api/cron/set-completed-goals",
      "schedule": "0 0 * * *"
    }
  ]
}

本地手动触发该接口时一切正常,但在Vercel上手动触发Cron Job后,日志显示返回200状态码:

200
[GET] /api/cron/set-completed-goals

但数据库中并未产生任何变更,请问问题出在哪里以及如何解决?


可能的原因及解决方法
  • 数据库环境不匹配
    本地使用开发数据库,而Vercel部署的项目可能连接的是生产数据库,或是环境变量配置错误。检查Vercel项目的「Environment Variables」设置,确认DATABASE_URL等数据库连接参数指向正确的目标数据库,且配置已在部署时生效。

  • Prisma Client未在Vercel上正确生成
    Vercel部署过程中可能未执行prisma generate命令,导致缺少适配生产环境的Prisma Client。在项目package.json的scripts中添加"postinstall": "prisma generate",确保部署时自动生成Client。

  • 数据库访问权限限制
    Vercel的Cron Job运行在边缘环境,可能被数据库的防火墙或私有网络规则拦截。检查数据库的防火墙配置,允许Vercel的IP段访问;若使用Prisma Data Proxy,确认代理配置正确且已生效。

  • 代码逻辑存在并发覆盖或数据一致性问题
    当前代码先读取用户数据,再循环更新,若用户的completedGoals被其他请求修改,会导致数据覆盖。建议优化代码,使用Prisma内置的push操作符,并减少多次数据库查询:

    export async function GET() {
      // 直接获取所有达标目标及关联用户
      const completedGoals = await prisma.goal.findMany({
        where: { percentage: { gte: 100 } },
        include: { user: true }
      });
    
      if (completedGoals.length === 0) {
        return NextResponse.json({ message: '无需要更新的完成目标' });
      }
    
      // 批量生成事务操作
      const transactions = completedGoals.flatMap(goal => [
        prisma.user.update({
          where: { id: goal.userId },
          data: { completedGoals: { push: goal.id } } // 用push避免数据覆盖
        }),
        prisma.goal.update({
          where: { id: goal.id },
          data: { percentage: 0 }
        })
      ]);
    
      await prisma.$transaction(transactions);
      return NextResponse.json({ message: `已更新${completedGoals.length}个完成目标` });
    }
    
  • 缺少执行日志定位问题
    虽然返回200,但无法确认代码内部执行情况。在代码中添加关键步骤的日志,然后查看Vercel的函数日志:

    export async function GET() {
      console.log('开始执行完成目标更新任务');
      const users = await prisma.user.findMany();
      console.log(`共查询到${users.length}个用户`);
    
      let updatedCount = 0;
      for (const user of users) {
        const goals = await prisma.goal.findMany({ where: { userId: user.id } });
        console.log(`用户${user.id}有${goals.length}个目标`);
    
        for (const goal of goals) {
          if (goal?.percentage ?? 0 >= 100) {
            console.log(`正在更新用户${user.id}的目标${goal.id}`);
            await prisma.$transaction([...]);
            updatedCount++;
          }
        }
      }
      console.log(`本次任务共更新${updatedCount}个目标`);
      return NextResponse.json({ message: `Completed goals updated: ${updatedCount} items` });
    }
    

通过日志可以确认是否读取到数据、事务是否执行,快速定位问题环节。


内容的提问来源于stack exchange,提问作者ozansozuoz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 11:17:47