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

Vercel无服务器函数日志串错:读API出现写API错误栈的原因?

问题分析与解决方案

核心现象

部署在Vercel的Next.js 14无服务器函数中,仅执行Firestore读操作的API(A-J)日志中出现了写操作API(W)的调用栈,且伴随Firestore的DEADLINE_EXCEEDED超时错误,尽管代码无显式全局状态共享,且已排除中间件影响。

可能原因及对应排查/解决方法

1. 无服务器函数容器复用导致Firestore客户端共享

Vercel的无服务器函数会复用运行容器以优化冷启动性能。如果Firestore客户端是在模块级别初始化(而非请求处理函数内部),同一容器内的不同API路由会共享该客户端实例。当API W的写操作超时后,客户端的错误上下文或连接状态可能未被正确清理,导致后续读API请求的日志中带上之前写请求的调用栈。

解决/排查:

  • 将Firestore客户端的初始化逻辑移至API路由的请求处理函数内部,确保每个请求使用独立的客户端实例。
  • 启用Next.js的dynamic: 'force-dynamic'配置,强制每个API路由使用独立的运行环境。

2. Next.js打包时API路由共享代码Chunk

从日志中的/var/task/.next/server/chunks/4483.js可以看出,API W的代码可能和读API被打包到了同一个共享Chunk中。当API W的写操作抛出错误,错误栈中的路径指向共享Chunk,Vercel的日志系统可能错误地将该错误关联到了同时使用该Chunk的读API请求。

解决/排查:

  • 在next.config.js中配置experimental.serverComponentsExternalPackages,将Firestore相关依赖标记为外部包,避免跨路由共享。
  • 使用自定义打包规则,将API W的路由代码单独拆分到独立Chunk中。

3. Firestore客户端重试机制的跨请求状态污染

Google Cloud Firestore客户端依赖google-gax库处理重试逻辑。如果客户端实例被共享,重试过程中的状态(如超时计时器、重试次数)可能未在请求间重置,导致读请求的日志中混入之前写请求的错误栈信息。

解决/排查:

  • 为每个API请求单独配置Firestore客户端的超时和重试参数,覆盖全局默认值:
    const db = initializeFirestore(app, {
      settings: {
        timeoutSeconds: 30,
        retrySettings: {
          maxRetries: 2,
        },
      },
    });
    
  • 在请求处理完成后,显式销毁客户端连接(如果支持)。

4. Vercel日志系统的错误关联

Vercel的日志系统可能基于容器ID、请求元数据等进行日志关联,偶尔会出现误关联情况,将API W的错误日志附加到读API的请求日志中。

解决/排查:

  • 在Vercel控制台中按API路由路径过滤日志,确认错误是否真的来自读API请求,还是日志系统的误关联。
  • 为每个API请求添加唯一的请求ID,在日志中输出该ID,便于区分不同请求的日志。

附用户提供的错误日志

Error adding document: Error: 4 DEADLINE_EXCEEDED: Deadline exceeded after 109.873s,name resolution: 0.001s,metadata filters: 0.022s,LB pick: 0.003s,remote_addr=1.95:443
    at callErrorFromStatus (/var/task/node_modules/.pnpm/@grpc+grpc-js@1.10.8/node_modules/@grpc/grpc-js/build/src/call.js:31:19)
    at Object.onReceiveStatus (/var/task/node_modules/.pnpm/@grpc+grpc-js@1.10.8/node_modules/@grpc/grpc-js/build/src/client.js:193:76)
    at Object.onReceiveStatus (/var/task/node_modules/.pnpm/@grpc+grpc-js@1.10.8/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:360:141)
    at Object.onReceiveStatus (/var/task/node_modules/.pnpm/@grpc+grpc-js@1.10.8/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:323:181)
    at /var/task/node_modules/.pnpm/@grpc+grpc-js@1.10.8/node_modules/@grpc/grpc-js/build/src/resolving-call.js:129:78
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
for call at
    at ServiceClientImpl.makeUnaryRequest (/var/task/node_modules/.pnpm/@grpc+grpc-js@1.10.8/node_modules/@grpc/grpc-js/build/src/client.js:161:32)
    at ServiceClientImpl.<anonymous> (/var/task/node_modules/.pnpm/@grpc+grpc-js@1.10.8/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)
    at /var/task/node_modules/.pnpm/@google-cloud+firestore@7.7.0/node_modules/@google-cloud/firestore/build/src/v1/firestore_client.js:242:29
    at /var/task/node_modules/.pnpm/google-gax@4.3.3/node_modules/google-gax/build/src/normalCalls/timeout.js:44:16
    at repeat (/var/task/node_modules/.pnpm/google-gax@4.3.3/node_modules/google-gax/build/src/normalCalls/retries.js:80:25)
    at /var/task/node_modules/.pnpm/google-gax@4.3.3/node_modules/google-gax/build/src/normalCalls/retries.js:119:13
    at OngoingCallPromise.call (/var/task/node_modules/.pnpm/google-gax@4.3.3/node_modules/google-gax/build/src/call.js:67:27)
    at NormalApiCaller.call (/var/task/node_modules/.pnpm/google-gax@4.3.3/node_modules/google-gax/build/src/normalCalls/normalApiCaller.js:34:19)
    at /var/task/node_modules/.pnpm/google-gax@4.3.3/node_modules/google-gax/build/src/createApiCall.js:112:30
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Caused by: Error
    at WriteBatch.commit (/var/task/node_modules/.pnpm/@google-cloud+firestore@7.7.0/node_modules/@google-cloud/firestore/build/src/write-batch.js:433:23)
    at DocumentReference.create (/var/task/node_modules/.pnpm/@google-cloud+firestore@7.7.0/node_modules/@google-cloud/firestore/build/src/reference.js:332:14)
    at CollectionReference.add (/var/task/node_modules/.pnpm/@google-cloud+firestore@7.7.0/node_modules/@google-cloud/firestore/build/src/reference.js:2854:28)
    **at g (/var/task/.next/server/app/api/user-history/route.js:1:1716)//HERE
    at h (/var/task/.next/server/app/api/user-history/route.js:1:1863)//HERE
    at y (/var/task/.next/server/app/api/user-history/route.js:1:2107)**
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async /var/task/.next/server/chunks/4483.js:1:877
    at async /var/task/.next/server/chunks/4483.js:1:752
    at async /var/task/node_modules/.pnpm/next@14.2.3_@babel+core@7.24.4_react-dom@18.3.1_react@18.3.1/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:34666 {
  code: 4,
  details: 'Deadline exceeded after 109.873s,name resolution: 0.001s,metadata filters: 0.022s,LB pick: 0.003s,remote_addr=172.253.115.95:443',
  metadata: Metadata { internalRepr: Map(0) {}, options: {} },
  note: 'Exception occurred in retry method that was not classified as transient'
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 01:54:55