【发布时间】:2019-07-30 21:30:03
【问题描述】:
问题
我正在通过 Dialogflow 使用托管在 Firebase Google Functions 上的 Node.js 的 Actions on Google 库开发一个 Actions on Google 应用程序(用于 Google Home)。我经常但不定期地(并且难以复制)遇到错误,迫使 Google 上的操作(模拟器或 Google Home 本身)关闭我的应用程序。我将所有 Dialogflow 意图(包括回退)路由到我的 webhook 实现,并且 - 基于日志文件 - webhook 快速响应(在 ~200 毫秒内)并具有有效响应(调查 JSON 响应)。但是,Actions on Google 似乎拒绝响应并触发 Dialogflow 默认文本响应。 我最担心的是,它发生在对话的不同阶段,有时已经在 Welcome 事件中。 还值得注意的是 - 即使履行在毫秒 (~200) 内响应,Actions on Google / Dialogflow 需要时间,而且 - 我相信 - 有一个超时。以下是我对潜在原因的探索。但坦率地说,我没有想法。
-- 编辑--
该服务现在似乎运行得更好了 - 我没有遇到此错误。通过使用全局数据库并将其传递,我已更改代码以减少调用 admin.firestore() 的频率。我有一种预感,可能同时调用了 https 函数,这可能会以某种方式导致格式错误的响应。
const database = admin.firestore();
// code
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'functionname') {
exports.functionname = functions.https.onRequest((req, res) => {
require('./functions').functionname(req, res, database);
});
}
我还在我的意图处理中发现了一个缺陷,导致没有匹配的意图。我已经重组了 Dialogflow 意图,以减少这种无意图的可能性(我基本上做了一个两步问题来确定用户的意图)。但是,由于 webhook 确实响应正确,我不认为这是问题所在。不过,我觉得这是一个奇怪的错误 - 所以如果有人有更多的指点,请!
-- 结束编辑--
日志
从 Google 函数日志中可以看到,这是来自 webhook 的响应 - 表示向 Dialogflow 应用发送响应。
Function execution took 289 ms, finished with status code: 200
Response {
"status": 200,
"headers": {
"content-type": "application/json;charset=utf-8"
},
"body": {
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [{
"simpleResponse": {
"textToSpeech": "Welcome back! Which Widget do you want to work with?"
}
}]
}
}
},
"outputContexts": [{
"name": "****anonymized****/contexts/widget",
"lifespanCount": 1
},
{
"name": "***anonymized****/contexts/_actions_on_google",
"lifespanCount": 99,
"parameters": {
"data": "{\"started\":1552071670}"
}
}
]
}
}
但是,这就是 Actions on Google 控制台所显示的内容。 textToSpeech 响应是默认文本响应,DialogFlow 可以在执行失败时回退到该响应(如 https://medium.com/google-developers/debugging-common-actions-on-google-errors-7c8527378d27 所建议的那样)
{
"conversationToken": "[]",
"finalResponse": {
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Sorry! I cannot access my online service. Please try again!"
}
}
]
}
},
"responseMetadata": {
"status": {
"code": 14,
"message": "Webhook error (206)"
},
"queryMatchInfo": {
"queryMatched": true,
"intent": "e0bf4b96-9440-4545-a8a6-d0915cacd34f"
}
}
}
stackdriver 日志还指出后一种情况,即收到来自 Dialogflow 的默认响应。
想法
我已尝试在模拟器、手机和 Google Home 上复制此错误。它发生在不同的时刻,尽管似乎比以前更频繁地发生。我的三个预感如下:
- 过载。我的 Google Functions 包含 8 个函数,包括 Dialogflow 应用程序。也许如果在给定时刻也经常调用其他函数,那么处理来自 Dialogflow(Google 助手)的 https 请求的 Dialogflow 应用程序会出现问题。但是,我不明白这应该如何发生。我可以通过在具有两个不同帐户的两台设备上调用该应用程序来复制(有时)该问题。但由于它也发生在一个帐户上,我认为这不是唯一的问题。我已按照此提示减少过载(https://stackoverflow.com/a/47985480/7053198),但这似乎对我的问题没有帮助。那么 Google Functions 的升级是否会成为问题?
- Promise hell。我正在使用许多 Promise(或更多回调)与 Firestore 数据库通信以检索用户数据。但是,我可以非常快速地调用这些意图,并且它们可以很好地解决 - 直到它们无法解决的地步。下面是这样一个意图的 sn-p。
- 我的应用的大小。 Intent 的数量变得相当大,Google Functions 和 Firestore 数据库之间有很多通信。我只是不知道这会如何影响 Dialogflow 拒绝看似正确的响应。
意图与承诺 sn-p:
app.intent(I.WIDGETTEST, conv => {
let database = admin.firestore();
let offline = [];
return database.collection('users').doc(conv.user.storage.userId).collection('widgets').get()
.then((snapshot) => {
const promises = [];
snapshot.forEach(doc => {
if (doc.data().active) {
if ((moment().unix()-doc.data().server.seen) > 360){
offline.push(doc.data().name);
}
promises.push(doc.ref.update({'todo.test': true}));
}
});
return Promise.all(promises);
})
.then(()=>{
conv.contexts.set(C.WIDGET, 1);
return conv.ask("Testing in progress. Which Widget do you want to work with now?");
})
.catch((err) => {
console.log(err)
throw err;
});
});
问题示例日志
为了更好地衡量,这里有来自堆栈驱动程序方面的三个日志条目:
{
"textPayload": "Sending request with post data: {\"user\":{\"userId\":\"***anonymized***\",\"locale\":\"en-US\",\"lastSeen\":\"2019-03-08T18:54:47Z\",\"userStorage\":\"{\\\"data\\\":{\\\"userId\\\":\\\"***anonymized***\\\"}}\",\"idToken\":\"eyJhbGciOiJSUzI1NiIsImtpZCI6ImNmMDIyYTQ5ZTk3ODYxNDhhZDBlMzc5Y2M4NTQ4NDRlMzZjM2VkYzEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE1NTIwNzEzNjAsImF1ZCI6Ijk4NzgxNjU4MTIzMC1ibWVtMm5wcTRsNnE3c2I5MnVpM3BkdGRhMWFmajJvNy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwMjk3OTk3NzIyNTM3NjY4MDEyOSIsImVtYWlsIjoiZGF2aWR2ZXJ3ZWlqQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoiRCBWZXJ3ZWlqIiwicGljdHVyZSI6Imh0dHBzOi8vbGg2Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8taldtOFd3eE5iS3MvQUFBQUFBQUFBQUkvQUFBQUFBQUFyLUUvNEE2UmJiYVNwem8vczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IkQiLCJmYW1pbHlfbmFtZSI6IlZlcndlaWoiLCJpYXQiOjE1NTIwNzE2NjAsImV4cCI6MTU1MjA3NTI2MCwianRpIjoiYjE4MDYwMjc0YmE4MjJhYzFhYzc0MTYwZjI2YWM2MDk3MzBmZDY4ZSJ9.Y9G0qo0Gf28-noF7RYPhtfHRuA7Qo6bCBSuN56Y0AtgIXaQKZjnmYvABIt9u8WQ1qPWwQc3jOLyhfoXIk8j0zhcQ0M0oc7LjkBwVCgFnJHvUAiV5fGEqQa95pZyrZhYmHipTDdwk0UhJHFGJOXAHDPP6oBSHKC9h48jqUjVszz6iEy4frV0XIKIzRR2U2iY6OgJuxPsV0A7xNjvLXiMmwaRUVtlj9CPmiizd3G2PhqD5C54Fy2Qg5ch89qMOA10vNB5B4AX9pmAXHpmtIqFo7ljvAeGAj-pRuqyMllz2awAdvqqOFRERDYfm5Fyh7N0l1OhR2A2XRegsUIL1I1EVPQ\"},\"conversation\":{\"conversationId\":\"ABwppHH8PXibDZg8in1DjbP-caFy67Dtq025k_Uq2ofoPNXKtiPXrbJTmpGVUnVy-aY6H1MeZCFIpQ\",\"type\":\"NEW\"},\"inputs\":[{\"intent\":\"actions.intent.MAIN\",\"rawInputs\":[{\"inputType\":\"KEYBOARD\",\"query\":\"Talk to ***anonymized appname***\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"}]}],\"requestType\":\"SIMULATOR\"}.",
"insertId": "120zsprg2nqfayb",
"resource": {
"type": "assistant_action",
"labels": {
"action_id": "actions.intent.MAIN",
"project_id": "***anonymized***",
"version_id": ""
}
},
"timestamp": "2019-03-08T19:01:00.243055001Z",
"severity": "DEBUG",
"labels": {
"channel": "preview",
"source": "AOG_REQUEST_RESPONSE",
"querystream": "GOOGLE_USER"
},
{
"textPayload": "Received response from agent with body: HTTP/1.1 200 OK\r\nServer: nginx/1.13.6\r\nDate: Fri, 08 Mar 2019 19:01:10 GMT\r\nContent-Type: application/json;charset=UTF-8\r\nContent-Length: 330\r\nX-Cloud-Trace-Context: 7761b69610701e0a7d18cbc69eef9bde/3001560133061614360;o=0\r\nGoogle-Actions-API-Version: 2\r\nAccess-Control-Allow-Credentials: true\r\nVia: 1.1 google\r\nAlt-Svc: clear\r\n\r\n{\"conversationToken\":\"[]\",\"finalResponse\":{\"richResponse\":{\"items\":[{\"simpleResponse\":{\"textToSpeech\":\"Sorry! I cannot access my online service. Please try again!\"}}]}},\"responseMetadata\":{\"status\":{\"code\":14,\"message\":\"Webhook error (206)\"},\"queryMatchInfo\":{\"queryMatched\":true,\"intent\":\"e0bf4b96-9440-4545-a8a6-d0915cacd34f\"}}}.",
"insertId": "120zsprg2nqfayc",
"resource": {
"type": "assistant_action",
"labels": {
"project_id": "***anonymized***",
"version_id": "",
"action_id": "actions.intent.MAIN"
}
},
"timestamp": "2019-03-08T19:01:10.376894030Z",
"severity": "DEBUG",
"labels": {
"channel": "preview",
"source": "AOG_REQUEST_RESPONSE",
"querystream": "GOOGLE_USER"
},
"logName": "projects/***anonymized***/logs/actions.googleapis.com%2Factions",
"trace": "projects/987816581230/traces/ABwppHH8PXibDZg8in1DjbP-caFy67Dtq025k_Uq2ofoPNXKtiPXrbJTmpGVUnVy-aY6H1MeZCFIpQ",
"receiveTimestamp": "2019-03-08T19:01:10.389139428Z"
},
{
"textPayload": "MalformedResponse: Webhook error (206)",
"insertId": "1d4bzl9g3lossug",
"resource": {
"type": "assistant_action",
"labels": {
"project_id": "***anonymized***",
"version_id": "",
"action_id": "actions.intent.MAIN"
}
},
"timestamp": "2019-03-08T19:01:10.377231474Z",
"severity": "ERROR",
"labels": {
"channel": "preview",
"source": "JSON_RESPONSE_VALIDATION",
"querystream": "GOOGLE_USER"
},
"logName": "projects/***anonymized***/logs/actions.googleapis.com%2Factions",
"trace": "projects/987816581230/traces/ABwppHH8PXibDZg8in1DjbP-caFy67Dtq025k_Uq2ofoPNXKtiPXrbJTmpGVUnVy-aY6H1MeZCFIpQ",
"receiveTimestamp": "2019-03-08T19:01:10.388395945Z"
}
救命!
非常感谢任何有助于解决此问题的帮助或指导。让我知道您是否曾经遇到过这种情况、有潜在的解决方案或希望查看代码或日志的更多详细信息。非常感谢!
【问题讨论】:
-
关于 Promise 的潜在复杂性,您可能需要重构以使用带有 async/await 调用的 Node 8。然后事情会变得更加精简。
标签: node.js google-cloud-functions dialogflow-es actions-on-google