我正在尝试将我的 Alexa 技能发布到 lambda 代码中的 MQTT 代理。但它只是偶尔发布。有人可以告诉我我错过了什么吗?这是我的代码:
const Alexa = require('ask-sdk-core');
const mqtt = require("mqtt");
const protocol = 'mqtt'
const host = 'm21.cloudmqtt.com'
const port = '14297'
const clientId = `mqtt_${Math.random().toString(16).slice(3)}`
const connectUrl = `${protocol}://${host}:${port}`
console.log(connectUrl);
const client = mqtt.connect(connectUrl, {
clientId,
clean: false,
connectTimeout: 4000,
username: '****',
password: '***',
reconnectPeriod: 1000,
})
client.on('connect', function(connack) {
console.log("MQTT Client connected " + JSON.stringify(connack));
// publish a message to a topic
client.publish('/IoTmanager/YardESP/Garage_close3/control', '{"status":0}', function() {
console.log("Message is published");
client.end(); // Close the connection when published
});
});
client.on('end', () => {
console.log('Connection to MQTT broker ended');
});
//
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'Would you like to open ur shut the Garage Door?';
console.log("MQTT Connecting");
/*client.on("connect", () => {
console.log("MQTT Connected");
client.publish("presence", "Hello mqtt");
});*/
//
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Would you like to open ur shut the Garage Door?', speechText)
.getResponse();
}
};
const GarageDoorCloseIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'GarageDoorCloseIntent';
},
handle(handlerInput) {
const speechText = 'Closing The garage door!';
console.log("MQTT Options: ", speechText);
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Closing The garage door!', speechText)
.getResponse();
}
};
const GarageDoorOpenIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'GarageDoorOpenIntent';
},
handle(handlerInput) {
const speechText = 'Opening The garage door!';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Opening The garage door!', speechText)
.getResponse();
}
};
const HelpIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speechText = 'You can ask me the weather!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('You can ask me the weather!', speechText)
.getResponse();
}
};
const CancelAndStopIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent'
|| Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent');
},
handle(handlerInput) {
const speechText = 'Goodbye!';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Goodbye!', speechText)
.withShouldEndSession(true)
.getResponse();
}
};
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest';
},
handle(handlerInput) {
// Any clean-up logic goes here.
return handlerInput.responseBuilder.getResponse();
}
};
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`Error handled: ${error.message}`);
return handlerInput.responseBuilder
.speak('Sorry, I don\'t understand your command. Please say it again.')
.reprompt('Sorry, I don\'t understand your command. Please say it again.')
.getResponse();
}
};
let skill;
exports.handler = async function (event, context) {
console.log(`REQUEST++++${JSON.stringify(event)}`);
console.log(context);
if (!skill) {
skill = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
GarageDoorCloseIntentHandler,
GarageDoorOpenIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
)
.addErrorHandlers(ErrorHandler)
.create();
}
const response = await skill.invoke(event, context);
console.log(`RESPONSE++++${JSON.stringify(response)}`);
return response;
};
我尝试调用 Alexa 技能,并从 Alexa 获得了正确的响应,但只有零星的消息发布到 MQTT 代理。
您是否有可能将其连接到 2 个不同的子网,其中一个子网没有到 Internet 的路由?
出于好奇,我通过 Amazon Q Developer(免费套餐)运行了您的问题:
Lambda 函数在连接到 Internet 上的服务时可能会出现偶发问题的原因有哪些?
Lambda 函数在连接到 Internet 上的服务时可能会遇到偶发问题,原因有多种。让我们探讨一些常见原因:1
VPC 配置:如果您的 Lambda 函数连接到 VPC,它可能会失去互联网访问权限。当函数位于 VPC 中时,所有出站请求都会经过 VPC。要访问 Internet,VPC 需要在公有子网中正确配置 NAT 网关以允许出站流量。 [2]
冷启动:一段时间未调用的 Lambda 函数可能会遇到“冷启动”。在冷启动期间,正在设置 Lambda 环境,这可能会导致延迟,并可能导致尝试连接到外部服务时超时。
DNS 解析问题:可能会出现偶发性 DNS 解析问题,特别是当 Lambda 函数在短时间内发出大量请求时。这可能会导致间歇性连接失败。 [3]
速率限制:如果您的 Lambda 函数频繁向外部服务发出请求,您可能会达到该服务施加的速率限制。这可能会导致偶发的连接失败或超时。
网络拥塞:AWS 基础设施或公共互联网中的临时网络拥塞或路由问题可能会导致间歇性连接问题。
资源限制:如果您的 Lambda 函数内存不足或达到执行时间限制,则可能难以一致地建立或维护连接。
弹性网络接口 (ENI) 限制:Lambda 为附加到函数的子网和安全组的每个组合创建一个 ENI。如果您接近限制(默认为每个 VPC 250 个),您可能会遇到偶发的连接问题。
第三方服务问题:您尝试连接的外部服务可能会遇到自己的间歇性问题或停机。
安全组配置:如果您的 Lambda 位于 VPC 中,请确保关联的安全组允许到互联网的出站流量。
并发执行:如果您的函数遇到高并发,您可能会达到 Lambda 服务配额,这可能会导致偶发故障。
要解决这些问题,您可以:
检查您的 VPC 配置(如果适用)。
在代码中实现正确的错误处理和重试机制。
使用 AWS X-Ray 跟踪请求并确定发生故障的位置。
在 CloudWatch 中监控函数的性能指标。
实施日志记录以捕获有关连接问题的更多详细信息。
[Python 代码示例]
此示例实现了一个带有指数退避的简单重试机制,这可以帮助缓解一些偶发的连接问题。请记住根据您的具体需求和您要连接的服务的特征调整 max_retries 和 retry_delay 值。