我有一个云函数,它调用一个复杂的任务(包含许多不同的异步任务)。在这些任务结束时,将发送一个事件“已完成”,并由将终止的云函数捕获,如:
exports.myFunction = functions.https.onRequest(async (request: any, response: any) => {
cors(request, response, async () => {
doSomethingComplex(); // no returned value possible here, but many asynchronous tasks done
eventEmitter.on('finished', (data) => { // finished is properly sent at the end of the asynchronous tasks
functions.logger.debug('done : ', data); // is always clean with only 1 occurence at each function call
response.send({something: data.something}); // <--- THIS IS WHERE THE ERROR OCCURE
}
});
});目前,每个异步任务都在每个调用上完美地完成。但是,每两次中就有一次,response.send()与以下错误堆栈发生错误:
at ServerResponse.send (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:267:15)
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:530:11)
at ServerResponse.send (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:158:21)
at ServerResponse.header (/layers/google.nodejs.functions-framework/functions-framework/node_modules/express/lib/response.js:771:10)
at EventEmitter.<anonymous> (/workspace/lib/src/index.js:235:37)
Function execution took 3354 ms, finished with status: 'crash'我试着使用response.end(),我试图返回response.send(),但是一切都失败了。
我还记录了每一个异步任务,以确保它们在发送' finished‘事件之前都完成了,并且该部分的所有内容都是干净的。
我不明白如何在云函数被调用时精确地调用response.send()一次,但仍然每两次调用就触发一次Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client (1次成功,1次错误,1次成功,1次错误)。
这对我来说是有意义的,就像云函数在response.send()之后没有关闭一样(根据this answer,这是不可能的)
有人有主意吗?我会非常感激的!
发布于 2021-06-10 15:53:54
answer you linked讨论了云函数的生命周期。
当您向您的函数发出请求时,云函数网关将检查是否有任何“云函数执行器”是空闲/陈旧/非活动的。如果没有一个空闲,一个新的执行器将被冷启动并发送请求。如果一个人空闲,该执行者将被发送请求,以节省冷启动一个新的执行器。在处理请求时,通过发送返回结果(对于HTTPS事件云函数,这是通过使用res.end()或其变体之一完成的;对于大多数其他云函数,这是通过解析返回的Promise链来完成的),从而告诉网关“我完成了”。
返回结果后,“”被标记为空闲。空闲时,任何网络请求都会被阻塞,该执行器可能在任何时候被关闭(终止)。如上所述,如果一个空闲函数处理另一个请求,如果您没有正确地处理生命周期流,它可能会导致奇怪的副作用,它可能再次被标记为active。
因此,要正确处理流,您需要遵循以下步骤:
G 212
如果您需要做的工作需要一段时间,请将作业描述写入数据库(Firestore/RTDB),以便它可以由写入数据库触发的不同云函数处理,然后将结果发回作为查找该作业更新位置的说明。
从您的代码来看,eventEmitter似乎被定义为一个全局对象,当它在doSomethingComplex()中完成工作时,它会释放出"finished"事件。当第一次触发myFunction时,一切都很好。但是,如果myFunction被重用,第二个"finished"事件将被触发。这对于当前请求很好,但是前面的请求仍然订阅eventEmitter,并试图发送第二个响应,从而导致所看到的错误。
你有三个选择:
eventEmitter的私有版本来自doSomethingComplex() )。(解决方案评级:将Okay)doSomethingComplex()转换为Promise-returning函数。(解决方案评级:最佳)https://stackoverflow.com/questions/67921964
复制相似问题