NextAuth PrismaAdapter linkAccount在Vercel无限挂起,本地运行正常
NextAuth OAuth认证在Vercel生产环境linkAccount步骤挂起超时问题
问题现象
- 用户点击“Sign in with Google”
- Google OAuth认证成功完成
/api/auth/callback/google端点挂起- 数据库中成功创建User记录(约240ms)
- 调用
linkAccount()适配器方法创建Account记录 - Account INSERT操作始终无法完成,直至超时(5-10秒)
events.linkAccount事件从未触发(确认适配器方法未完成)
环境信息
- Next.js 15.1.6(App Router)
- NextAuth 4.24.13
- @auth/prisma-adapter 2.7.4
- 自定义生成客户端的Prisma
- @prisma/adapter-pg 6.1.0
- PostgreSQL(自托管,本地与Vercel均可访问)
- 部署于Vercel(Serverless函数)
Prisma Client配置(src/lib/prisma.ts)
import { PrismaClient } from "@/generated/prisma/client"; import { PrismaPg } from "@prisma/adapter-pg"; import { Pool } from "pg"; const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }; export const prisma = globalForPrisma.prisma || new PrismaClient({ adapter: new PrismaPg( new Pool({ connectionString: process.env.DATABASE_URL }) ), }); if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
NextAuth配置(src/lib/auth.ts)
import { PrismaAdapter } from "@auth/prisma-adapter"; import { prisma } from "./prisma"; const baseAdapter = PrismaAdapter(prisma); export const authOptions: NextAuthOptions = { adapter: { ...baseAdapter, // 添加10秒超时包装器调试(替代等待Vercel默认300秒超时) linkAccount: async (account: any) => { console.log('[linkAccount adapter] Called with account:', account); const start = Date.now(); try { const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('linkAccount timeout after 10s')), 10000) ); // 此处挂起 - 从未完成 const createPromise = prisma.account.create({ data: account }); const result = await Promise.race([ createPromise, timeoutPromise ]); console.log(`[linkAccount adapter] Completed in ${Date.now() - start}ms`); return result; } catch (error) { console.error('[linkAccount adapter] Error:', error); console.log(`[linkAccount adapter] Failed after ${Date.now() - start}ms`); throw error; } }, } as Adapter, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, allowDangerousEmailAccountLinking: true, }), ], session: { strategy: "jwt" }, };
已验证内容
网络连接无问题
- tcpdump确认Vercel成功连接PostgreSQL
- TCP握手完成,数据已交换
- 同一端点的其他数据库操作(User创建、SELECT查询)正常运行
Vercel日志显示
[linkAccount adapter] Called with account: { userId: '....', ... } [linkAccount adapter] Error: Error: linkAccount timeout after 5s [linkAccount adapter] Failed after 10006ms
数据库日志显示
- User INSERT查询执行成功
- Account INSERT查询从未出现在PostgreSQL日志中
- 无锁、无长时间运行的查询
- pg_stat_activity显示无挂起连接
浏览器显示
/api/auth/callback/google端点处于“pending”状态约10秒- 随后跳转到NextAuth错误页面
已尝试方案
- ✅ 添加带显式超时的自定义连接池 - 无变化
- ✅ 使用
$executeRaw原生SQL替代prisma.account.create()- 仍挂起 - ✅ 将连接池大小从1增加到10 - 无变化
- ✅ 验证iptables/防火墙规则 - tcpdump显示连接成功
- ✅ 简化Prisma配置为官方单例模式 - 仍挂起
- ✅ 移除适配器重写 - 基础PrismaAdapter同样挂起
疑问
- 为何
linkAccount()仅在Vercel Serverless环境挂起,本地正常? @prisma/adapter-pg+ pg Pool + Serverless函数是否存在已知问题?- 是否应在Vercel使用Prisma Accelerate或PgBouncer等外部连接池?
- pg Pool是否与Vercel的Serverless冷启动不兼容?
根据数据库日志,查询从未到达PostgreSQL,表明问题出在Prisma/适配器层而非数据库本身。
补充:Claude代码无法解决该问题,需休息后次日再排查。
更新
休息很重要。
已执行操作
- 将本地应用连接到生产数据库,可正常写入Accounts表(本地环境)
- 尝试登录生产环境,登录成功(Vercel环境)
- 在应用中更新个人资料信息(Vercel环境)
结论
- ✅ Vercel可正常写入数据库(Session功能正常)
- ✅ Vercel可通过API路由手动写入Account表
- ✅ 本地开发环境→生产数据库的所有操作(包括linkAccount)均正常
- ❌ 仅OAuth回调期间的
linkAccount在Vercel Serverless环境挂起
内容的提问来源于stack exchange,提问作者Zero
相关产品推荐
相关产品推荐

