使用Dialogflow Fulfillment通过Twilio发送SMS失败求助
排查Dialogflow Fulfillment调用Twilio超时问题(DEADLINE_EXCEEDED)
问题场景
基于Dialogflow开发的聊天机器人,通过Fulfillment触发Twilio服务发送SMS给人工团队,部署无报错,但Fulfillment返回Webhook call failed. Error: DEADLINE_EXCEEDED, State: URL_TIMEOUT, Reason: TIMEOUT_WEB。
核心问题分析
- 函数命名冲突导致无限递归:代码中存在两个同名的
enviarmensagem函数——一个是全局的Twilio短信发送函数,另一个是Intent处理函数。当Intent触发时,handler内部调用enviarmensagem(agent.session)会优先指向当前作用域的handler函数,导致无限递归,最终触发超时。 - 异步操作未正确处理:Twilio的
messages.create是异步Promise操作,原代码没有等待其完成,即使解决命名冲突,也可能存在未处理的异步逻辑,影响Webhook响应时机。 - 依赖与Node版本过旧:package.json中Node版本为10,相关依赖版本较低,可能存在兼容性或性能问题。
解决方案
1. 修复函数命名冲突
将全局的短信发送函数重命名,避免与Intent handler重名,比如改为sendTwilioSMS。
2. 正确处理异步Promise
在Intent handler中返回Twilio调用的Promise,确保Dialogflow等待异步操作完成(或根据需求选择异步执行,但需避免未处理Promise)。
3. 升级依赖与Node版本
更新package.json中的Node版本为当前支持的稳定版(如16),并升级相关依赖到兼容版本。
修改后的代码示例
'use strict'; const functions = require('firebase-functions'); const {WebhookClient} = require('dialogflow-fulfillment'); const accountSid = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; const authToken = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; const twilio = require('twilio')(accountSid, authToken); // 重命名全局短信发送函数,避免命名冲突 function sendTwilioSMS(usuario){ const client = twilio; // 已在顶部初始化,无需重复创建实例 return client.messages .create({ body: 'Teste OK', to: '+55XXXXXXXXXX', from: '+1XXXXXXXXXXX' }) .then((message) => { console.log(message.sid); return message; }) .catch(err => { console.error('Twilio发送错误:', err); throw err; }); } exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); // Intent处理函数 async function handleSendMessage(agent) { agent.add('Mensagem enviada'); // 等待Twilio短信发送完成 await sendTwilioSMS(agent.session); } let intentMap = new Map(); intentMap.set('Teste mensagem', handleSendMessage); try{ agent.handleRequest(intentMap); } catch(e){ console.error('Webhook处理错误:', e); agent.add('Ocorreu um erro ao enviar a mensagem'); agent.handleRequest(intentMap); } });
修改后的package.json示例
{ "name": "dialogflowFirebaseFulfillment", "description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase", "version": "0.0.1", "private": true, "license": "Apache Version 2.0", "author": "Google Inc.", "engines": { "node": "16" }, "scripts": { "lint": "semistandard --fix \"**/*.js\"", "start": "firebase serve --only functions:dialogflowFirebaseFulfillment", "deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment" }, "dependencies": { "actions-on-google": "^3.0.0", "firebase-admin": "^11.0.0", "firebase-functions": "^4.0.0", "dialogflow": "^1.2.0", "dialogflow-fulfillment": "^0.7.2", "twilio": "^4.0.0", "nodemailer": "^6.7.0" } }
额外检查项
- 确认Twilio的
accountSid和authToken正确,且目标手机号已验证(若使用Twilio试用版)。 - 检查Firebase Functions的超时设置,若需要更长时间处理,可在函数定义中添加
timeoutSeconds配置:
注意:Dialogflow Webhook的最大超时为10秒,因此Functions超时设置不应超过该值。exports.dialogflowFirebaseFulfillment = functions.runWith({ timeoutSeconds: 30 }).https.onRequest((request, response) => { // 函数逻辑 });
内容的提问来源于stack exchange,提问作者Erick Patrocínio
相关产品推荐
相关产品推荐

