我正在构建与AWS lambda函数相关的Alexa技能。出于某些目的,我需要发出http请求,由于我无法预测的连接延迟,这可能会失败。问题是,如果我使用的内存超过128Mb,或者执行时间超过7000ms,lambda会中断我的执行。由于我不想增加时间限制,因此我正在寻找一种方法来防止lambda向我的Alexa技能发送错误消息,该消息将告诉我发生了问题,但向自己发送了一条消息,指出连接可能很慢,Alexa无法找不到用户的要求。
我试图访问控制台报告以检查是否存在超时错误,但是我是Node.js的新手,所以我无法阻止lambda将此错误发送给Alexa。
这是我的lambda代码:
var https = require('https');
const fs = require('fs');
let speechOutput;
let reprompt;
let welcomeOutput = "Salve Guardiano, per ora puoi chiedermi cosa porta Xur questa settimana, quali cala la notte ci sono, dove si trova focolai o anche in che stato si trova la città sognante.";
let welcomeReprompt = "Come posso aiutarti?";
"use strict";
const Alexa = require('alexa-sdk');
const APP_ID = undefined; // TODO replace with your app ID (OPTIONAL).
speechOutput = '';
const handlers = {
'LaunchRequest': function () {
this.emit(':ask', welcomeOutput, welcomeReprompt);
},
'AMAZON.HelpIntent': function () {
speechOutput = 'Per ora puoi chiedermi cosa porta Xur questa settimana, quali cala la notte ci sono, dove si trova focolai o anche in che stato si trova la città sognante.';
this.emit(':ask', speechOutput);
},
'AMAZON.CancelIntent': function () {
speechOutput = 'Ok, cancello.';
this.emit(':tell', speechOutput);
},
'AMAZON.StopIntent': function () {
speechOutput = 'Arrivederci, non camperare troppo.';
this.emit(':tell', speechOutput);
},
'SessionEndedRequest': function () {
speechOutput = '';
//this.emit(':saveState', true);//uncomment to save attributes to db on session end
this.emit(':tell', speechOutput);
},
'AMAZON.NavigateHomeIntent': function () {
speechOutput = '';
//any intent slot variables are listed here for convenience
//Your custom intent handling goes here
speechOutput = "Chiedimi aiuto.";
this.emit(":ask", speechOutput);
},
'informazioni_settimanali': async function () {
//prendo il codice corrispondente allo slot comunicato
let activityID = this.event.request.intent.slots.activity.resolutions.resolutionsPerAuthority[0].values[0].value.id;
//prendo il token di accesso
let token = this.event.context.System.user.accessToken;
speechOutput = '';
speechOutput = await richiesta_activities(activityID);
speechOutput = speechOutput + "Posso fare altro per la tua luce?"
this.emit(":ask", speechOutput );
},
'xur_location': async function () {
speechOutput='Non ho ancora sviluppato questa funzionalità. Posso aiutarti in altro modo?';
this.emit(":ask", speechOutput, speechOutput);
},
'what_sells_xur': async function () {
//prendo il token di accesso
let token = this.event.context.System.user.accessToken;
if(token==null){
speechOutput = 'Per richiedere questo tipo di informazioni devi collegare il tuo account Bungie alla skill Spettro dall\'app Alexa.';
this.emit(":tellWithLinkAccountCard",speechOutput);
}else{
speechOutput='';
speechOutput = await xur_inventory(token);
speechOutput = speechOutput + " Posso fare altro per la tua luce?"
this.emit(":ask", speechOutput );
}
},
'Unhandled': function () {
speechOutput = "Perdonami, non ho capito.";
this.emit(':ask', speechOutput, speechOutput);
}
};
exports.handler = (event, context,callback) => {
const alexa = Alexa.handler(event, context);
alexa.appId = APP_ID;
// To enable string internationalization (i18n) features, set a resources object.
//alexa.resources = languageStrings;
alexa.registerHandlers(handlers);
//alexa.dynamoDBTableName = 'DYNAMODB_TABLE_NAME'; //uncomment this line to save attributes to DB
alexa.execute();
};
// END of Intent Handlers {} ========================================================================================
async function xur_inventory(token){
let Hash='2190858386'; //xur's hash
let endpoint = '/Platform/Destiny2/2/Profile/4611686018456602435/Character/2305843009289717384/Vendors/?components=vendorsales';
const response = await httpTokenGet(endpoint,token);
let ans='';
//console.log(response);
if(response.Response.sales.data[Hash]!=null){
let items = new Array();
var i=0;
let temp;
temp = response.Response.sales.data[Hash].saleItems;
for(var key in temp){
//console.log(key);
//console.log(temp[key].itemHash);
items[i]=temp[key].itemHash;
i++;
}
//LETTURA AGGIORNATA DAL WEB
let jsonendpoint = '/it/reducedCollectableInventoryItems.json';
const DestinyItems = await httpJsonGet(jsonendpoint);
//console.log(DestinyItems);
let itemsPlain = new Array();
let itemsType = new Array();
for(let i=0;i<items.length;i++){
if(DestinyItems[items[i]]!=null){
itemsPlain[i]=DestinyItems[items[i]].displayProperties.name;
itemsType[i]=DestinyItems[items[i]].itemTypeDisplayName;
//console.log(itemsPlain[i]);
//console.log(itemsType[i]);
}
}
ans = "Ecco cosa vende Xur: ";
for (var i=0;i<itemsPlain.length;i++){
ans = ans + itemsPlain[i] + " ("+ itemsType[i]+"). ";
}
return ans;
}else {
return "Mi spiace non riesco a trovare Xur. ";
}
}
async function richiesta_activities(activityID,token){
//this function returns the activity's infos selected by the user
let endpoint = '';
if(activityID==0){
//cala la notte
let Hash='2171429505';
endpoint = '/Platform/Destiny2/Milestones/';
const response = await httpGet(endpoint);
let nightfalls = new Array();
if(response.Response[Hash]!=null){
for(let i=0;i<3;i++){
nightfalls[i]=response.Response[Hash].activities[i].activityHash;
}
//LETTURA AGGIORNATA DAL WEB
let jsonendpoint = '/en/reducedActivities.json';
const Destinyactivities = await httpJsonGet(jsonendpoint);
let nightfallsPlain = new Array();
for(let i=0;i<3;i++){
nightfallsPlain[i]=Destinyactivities[nightfalls[i]].displayProperties.name;
console.log(nightfallsPlain[i]);
}
let ans = "Ecco i cala la notte che ho trovato: ";
for (var i=0;i<3;i++){
let end=nightfallsPlain[i].lengt;
nightfallsPlain[i]=nightfallsPlain[i].substring(10,end);
ans = ans + nightfallsPlain[i] + ", ";
}
return ans;
}
else{
return "Purtroppo non riesco ad aiutarti.";
}
}
else if(activityID==1){
//focolai
let Hash = '463010297';
endpoint = '/Platform/Destiny2/Milestones/';
const response = await httpGet(endpoint);
if(response.Response[Hash]!=null){
var flashpoint = response.Response[Hash].availableQuests[0].questItemHash;
console.log(flashpoint);
var text = '';
//LETTURA DAL WEB
let jsonendpoint = 'https://destiny.plumbing/en/raw/DestinyInventoryItemDefinition.json';
const DestinyFlashpoint = await httpJsonGet(jsonendpoint);
if(DestinyFlashpoint[flashpoint]!=null){
console.log(DestinyFlashpoint[flashpoint]);
let flashpointPlain = DestinyFlashpoint[flashpoint].displayProperties.name;
let location=flashpointPlain.substring(10,flashpointPlain.length);
return "Questa settimana, il focolaio si trova su "+location+".";
}else{
return "Purtroppo non riesco ad aiutarti.";
}
}else{
return "Purtroppo non riesco ad aiutarti.";
}
}else{
return "Devo ancora sviluppare le altre attività.";
}
}
function httpTokenGet(endpoint,token) {
return new Promise(((resolve, reject) => {
var options = {
host: 'www.bungie.net',
path: endpoint,
method: 'GET',
headers: {'X-API-KEY': 'xxxxxxxxxxxxxxxxxxxxxx',
'Authorization': 'Bearer '+ token},
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
function httpGet(endpoint) {
return new Promise(((resolve, reject) => {
var options = {
host: 'www.bungie.net',
path: endpoint,
method: 'GET',
headers: {'X-API-KEY': 'xxxxxxxxxxxxxxxxxxxxxx'},
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
function httpJsonGet(endpoint) {
return new Promise(((resolve, reject) => {
var options = {
host: 'destiny.plumbing',
path: endpoint,
method: 'GET',
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
此问题可能在函数async function richiesta_activities(activityID,token)
中出现
//LETTURA DAL WEB
let jsonendpoint = 'https://destiny.plumbing/en/raw/DestinyInventoryItemDefinition.json';
const DestinyFlashpoint = await httpJsonGet(jsonendpoint);
当我打电话给await httpJsonGet(jsonendpoint);
事实上,在测试lambda控制台时,会记录以下内容:
Response:
{
"errorMessage": "2019-03-27T17:21:48.437Z 855210e7-4c89-474b-af57-0bdd3e9d89d5 Task timed out after 7.01 seconds"
}
Request ID:
"855210e7-4c89-474b-af57-0bdd3e9d89d5"
Function Logs:
START RequestId: 855210e7-4c89-474b-af57-0bdd3e9d89d5 Version: $LATEST
2019-03-27T17:21:41.520Z 855210e7-4c89-474b-af57-0bdd3e9d89d5 Warning: Application ID is not set
END RequestId: 855210e7-4c89-474b-af57-0bdd3e9d89d5
REPORT RequestId: 855210e7-4c89-474b-af57-0bdd3e9d89d5 Duration: 7007.93 ms Billed Duration: 7000 ms Memory Size: 128 MB Max Memory Used: 128 MB
2019-03-27T17:21:48.437Z 855210e7-4c89-474b-af57-0bdd3e9d89d5 Task timed out after 7.01 seconds
但是Alexa说这项技术存在问题。 如何防止这种情况并独自处理以不返回错误?
编辑:感谢@Deiv超时处理程序的工作。
我仍然想找到一种访问lambda REPORT的方法,因为我注意到即使执行时间少于7000ms,我也可能会内存不足,并且很好地处理这种情况。
答案 0 :(得分:0)
您可以在函数本身超时之前设置内部超时和带有成功消息的回调。看起来可能像这样:
const self = this;
setTimeout(function(){
//after 6 seconds, exit function
self.emit(':tell', "The connection is too slow, nothing was found.");
process.exit();
}, 6000);
//rest of your code
由于setTimeout()异步运行,因此不会阻塞其余代码,但是它将在6秒钟后返回一条成功消息,从而避免了超时错误。
由OP编辑:
我添加了const self = this;
,因为在函数范围内这毫无意义。
感谢您@Deiv,现在可以使用了。
我仍然想找到一种访问lambda REPORT的方法,因为我注意到即使执行时间少于7000ms,我也可能会内存不足,并且很好地处理这种情况。