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

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同样挂起

疑问

  1. 为何linkAccount()仅在Vercel Serverless环境挂起,本地正常?
  2. @prisma/adapter-pg + pg Pool + Serverless函数是否存在已知问题?
  3. 是否应在Vercel使用Prisma Accelerate或PgBouncer等外部连接池?
  4. pg Pool是否与Vercel的Serverless冷启动不兼容?

根据数据库日志,查询从未到达PostgreSQL,表明问题出在Prisma/适配器层而非数据库本身。

补充:Claude代码无法解决该问题,需休息后次日再排查。

更新

休息很重要。

已执行操作

  1. 将本地应用连接到生产数据库,可正常写入Accounts表(本地环境)
  2. 尝试登录生产环境,登录成功(Vercel环境)
  3. 在应用中更新个人资料信息(Vercel环境)

结论

  1. ✅ Vercel可正常写入数据库(Session功能正常)
  2. ✅ Vercel可通过API路由手动写入Account表
  3. ✅ 本地开发环境→生产数据库的所有操作(包括linkAccount)均正常
  4. ❌ 仅OAuth回调期间的linkAccount在Vercel Serverless环境挂起

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:07:34