Next 13 App目录下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

