为啥 UnhandledPromiseRejectionWarning 只出现在生产中(Google Cloud Run)?
Posted
技术标签:
【中文标题】为啥 UnhandledPromiseRejectionWarning 只出现在生产中(Google Cloud Run)?【英文标题】:Why is UnhandledPromiseRejectionWarning only appearing in production (Google Cloud Run)?为什么 UnhandledPromiseRejectionWarning 只出现在生产中(Google Cloud Run)? 【发布时间】:2022-01-18 17:00:55 【问题描述】:我很难解决一些在我的笔记本电脑开发环境中运行良好的功能(即使我使用 NODE_ENV=production 运行它),但是当我将它部署到 Google Cloud Run 时,我会遇到错误,例如
Default
2021-12-15T12:16:35.016406Z at TCP.done (_tls_wrap.js:564:7)
Default
2021-12-15T12:16:35.016414Z(Use `node --trace-warnings ...` to show where the warning was created)
Default
2021-12-15T12:16:35.016426Z(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
Default
2021-12-15T12:16:35.116284Z(node:1) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Default
2021-12-15T12:16:35.116931Z(node:1) UnhandledPromiseRejectionWarning: Error: socket hang up
Default
2021-12-15T12:16:35.116954Z at connResetException (internal/errors.js:639:14)
Default
2021-12-15T12:16:35.116969Z at TLSSocket.socketCloseListener (_http_client.js:449:25)
Default
2021-12-15T12:16:35.116979Z at TLSSocket.emit (events.js:412:35)
Default
2021-12-15T12:16:35.116989Z at net.js:686:12
Default
2021-12-15T12:16:35.116999Z at TCP.done (_tls_wrap.js:564:7)
导致我的脚本停止。在我的本地版本中,它会继续运行而不会停止。这非常令人沮丧,因为我需要一直将代码上传到 Cloud Run 以测试我的代码。我正在盲目测试它,因为错误没有出现在我的开发版本中。
我对 Node.js 还是很陌生,并且经常在使用 .then()、链接 .then()、promise、使用 resolve() 时遇到困难,因此代码很可能是错误的。
我的问题在这里:
-
为什么这个错误只出现在 Cloud Run 上?
如何以相同的方式配置我的本地计算机,使其显示相同的警告和错误 - 以便解决此问题?
我的代码(简化):
function createOrUpdateSpotterData(data)
// NOTE: Data comes from API and not from DB, thus no info such as twitter_status
// TODO: Separate into a create or update, in order to not check twitter ID every time.
return new Promise( async function (resolve)
var twitterId = await twitterApi.getTwitterIdFromUsername(cleanedUsername)
data['twitter_numeric'] = twitterId
resolve(data)
).then( (data) =>
db.collection('spotters').doc(data.marker).set(data)
).catch( (error) => console.log(error) )
async function updateSpottersJsonToDb()
console.log("> updateSpottersJsonToDb")
return new Promise( (resolve, reject) =>
readStorageData(remote_files['spotters'])
.then( async (spotterListJson) =>
var spotterList = JSON.parse(spotterListJson)
await spotterList.forEach((spotter) =>
createOrUpdateSpotterData(spotter)
)
)
.then(() =>
resolve()
)
.catch((error) => console.error(error))
).catch((error) => console.error(error))
【问题讨论】:
对于初学者,您可以停止使用将现有 Promise 包装在另一个手动创建的 Promise 中的 Promise 反模式。当你这样做时,在错误处理中很容易出错,这是完全没有必要的。您可以只使用代码已经生成的第一个承诺 - 无需将其包装在新的承诺中。createOrUpdateSpotterData()
是异步的吗?仅供参考,await spotterList.forEach(...)
中的await
什么都不做,因为.forEach()
没有返回值并且不知道async
。 await
仅在您等待承诺时才做某事。如果此循环中有异步内容,请将其更改为普通的 for
循环和 await
循环内的实际异步操作。
另外,你知道.catch((error) => console.error(error))
会记录错误然后“吃掉”它,这样调用者就不会看到错误了吗?
感谢您的 cmets。我知道当我在编码时学习时,我可能会犯很多非常糟糕的错误。然而,我发现很难对 promise、.then 和 await 有一个很好的直觉。 1.你是什么意思,具体来说,承诺反模式。你的意思是在新的 Promise 中有 .then() 吗?
2. createOrUpdateSpotterData() 不是异步的。如果是这样,它会改变什么吗?感谢您提供关于 await 和 forEach 的提示,我有这种感觉,但无法确认。
【参考方案1】:
承认这一点很尴尬,但我对这个“只见树木不见森林”的“错误信息”的数量感到有点不知所措。毕竟这只是一个警告,通过过滤std.out
上的日志(在 Google Cloud Logs 上),我意识到这并没有导致我在应用程序中遇到的任何问题。
然而,这个问题的原因是我没有正确捕获我的 Promise 中的错误,这确实是另一个问题 (being discussed here)。
如果您稍后通过 Google 找到此内容,最好知道您可以使用 process.on()
隐藏此警告。
【讨论】:
以上是关于为啥 UnhandledPromiseRejectionWarning 只出现在生产中(Google Cloud Run)?的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 glTranslatef?为啥不直接更改渲染坐标?
为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?