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

基于Serverless GraphQL项目出现context.done被调用两次警告的问题

Fixing "context.done called twice" Warning in Apollo Server Lambda + Serverless

Let's break down why you're seeing this warning and how to fix it properly:

The Root Cause

Your current implementation mixes two incompatible Lambda handler patterns that trigger the double invocation warning:

  1. You’re using an async function for your handler, which tells AWS Lambda to wait for a returned Promise to resolve or reject.
  2. You’re passing a custom callback to graphqlLambda where you call context.done manually—but Apollo Server's graphqlLambda already handles invoking the callback/context.done internally.

When you commented out your manual context.done call, the request hung because you left the custom callback incomplete: Apollo expected your callback to finalize the request, but you never fulfilled that responsibility.

Solution 1: Async/Await (Cleanest Approach)

Leverage async/await to modify the response headers after Apollo generates the response, avoiding callback conflicts entirely:

import { graphqlLambda, graphiqlLambda, LambdaHandler } from 'apollo-server-lambda'
import lambdaPlayground from 'graphql-playground-middleware-lambda'
import { makeExecutableSchema } from 'graphql-tools'
import { resolvers } from './resolvers'
const typeDefs = require('./schema.gql')

const schema = makeExecutableSchema({ typeDefs, resolvers, logger: console })

export const graphqlHandler: LambdaHandler = async (event, context) => {
  // Let Apollo handle core request processing
  const response = await graphqlLambda({ schema })(event, context)
  
  // Add your CORS header to the response
  response.headers = {
    ...response.headers,
    'Access-Control-Allow-Origin': '*'
  }
  
  // Return the modified response (Lambda handles promise resolution automatically)
  return response
}

export const playgroundHandler = lambdaPlayground({ endpoint: '/graphql' })
export const graphiqlHandler: any = graphiqlLambda({ endpointURL: '/graphql' })

Solution 2: Apollo's Built-in Response Formatting

You can also set custom headers directly within Apollo's configuration using the formatResponse option, keeping all logic within Apollo's designed flow:

import { graphqlLambda, graphiqlLambda, LambdaHandler } from 'apollo-server-lambda'
import lambdaPlayground from 'graphql-playground-middleware-lambda'
import { makeExecutableSchema } from 'graphql-tools'
import { resolvers } from './resolvers'
const typeDefs = require('./schema.gql')

const schema = makeExecutableSchema({ typeDefs, resolvers, logger: console })

export const graphqlHandler: LambdaHandler = (event, context, callback) => {
  const handler = graphqlLambda({ 
    schema,
    formatResponse: (responseData) => ({
      ...responseData,
      headers: {
        ...responseData.headers,
        'Access-Control-Allow-Origin': '*'
      }
    })
  })
  
  // Let Apollo's handler manage the callback/context.done internally
  return handler(event, context, callback)
}

export const playgroundHandler = lambdaPlayground({ endpoint: '/graphql' })
export const graphiqlHandler: any = graphiqlLambda({ endpointURL: '/graphql' })

Why This Works

  • Async/Await Approach: By awaiting the result of graphqlLambda, you get the full response object, modify it, and return it. Lambda automatically recognizes the returned Promise and handles request completion correctly—no need for context.done at all.
  • FormatResponse Approach: Apollo lets you intercept and modify the response before it’s sent, keeping all request handling within its designed flow and avoiding conflicts with Lambda’s callback mechanism.

Key Takeaway

Never mix async/await with manual context.done/callback invocations in Lambda handlers. Pick one pattern and stick to it. For Apollo Server Lambda, using async/await to handle response modifications is the most straightforward and maintainable approach.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:27:18