J'ai un problème pour interroger ma base de données MySQL (hébergée à distance depuis AWS) à l'intérieur de ma fonction AWS Lambda.
Ceci est mon code, sauf pour les pièces dont j'ai besoin pour le reste de la fonction Lambda (qui est appelée pour une compétence Alexa):
var mysql = require('mysql');
var connection = mysql.createConnection({
Host : '<myserver>',
user : '<myusername>',
password : '<mypw>',
database : '<mydatabase>'
});
connection.connect(function(err){
if(!err) {
console.log("Database is connected ... nn");
}
else {
console.log("Error connecting database ... nn");
}
});
connection.query("INSERT INTO Users (user_id) VALUES ('TESTNAME')");
connection.end();
Cela fonctionne très bien lorsque je l'exécute avec un nœud à partir de mon invite de commande:
node index.js
J'utilise le module "mysql" installé via npm dans le répertoire avec index.js et le Zip et le télécharger sur ma fonction Lambda.
Encore une fois, cela fonctionne sur ma machine de développement, mais ne donne aucun indicateur lors du test de ma fonction Lambda pour expliquer pourquoi cela n'affecte pas du tout ma base de données.
Ma question s'étend à Alexa et Lambda autant qu'à l'utilisation correcte du module mysql Node.JS.
Voici mon code actuel pour ma Lambda, et le problème ici, bien sûr, est toujours que ma valeur de test -> un nom d'utilisateur appelé "TESTNAME" n'est pas ajouté à ma base de données MySQL.
Je mets la requête dans le rappel de connexion comme le premier commentaire le suggère, et je mets mon nouveau code au lieu de mettre à jour mon ancien code ci-dessus juste pour garder une trace de la façon dont je pense que le code devrait passer à la fonction Lambda d'Alexa :
Code mis à jour:
var mysql = require('mysql');
var connection = mysql.createConnection({
Host : '<myserver>',
user : '<myusername>',
password : '<mypw>',
database : '<mydatabase>'
});
exports.handler = (event, context) => {
try {
if (event.session.new) {
// New Session
console.log("NEW SESSION");
}
switch (event.request.type) {
case "LaunchRequest":
// Launch Request
console.log(`LAUNCH REQUEST`);
context.succeed(
generateResponse({},
buildSpeechletResponse("Welcome to an Alexa Skill, this is running on a deployed lamda function", true)
)
);
break;
case "IntentRequest":
// Intent Request
console.log(`Intent Request`);
console.log('Then run MySQL code:');
connection.connect(function(err) {
console.log('Inside connection.connect() callback');
if (!err) {
console.log("Database is connected ... ");
connection.query("INSERT INTO Users (user_id) VALUES ('TESTNAME')",
function(err, result) {
console.log("Inside connection.query() callback")
if (!err) {
console.log("Query Successful! Ending Connectection.");
connection.end();
} else {
console.log("Query error!");
}
});
} else {
console.log("Error connecting database ..." + err.message);
}
});
context.succeed(
generateResponse({},
buildSpeechletResponse("Welcome to the incredible intelligent MySQLable Alexa!", true)
)
);
break;
case "SessionEndedRequest":
// Session Ended Request
console.log(`SESSION ENDED REQUEST`);
break;
default:
context.fail(`INVALID REQUEST TYPE: ${event.request.type}`);
}
} catch (error) {
context.fail(`Exceptiodn: ${error}`)
}
};
//Helpers
buildSpeechletResponse = (outputText, shouldEndSession) => {
return {
outputSpeech: {
type: "PlainText",
text: outputText
},
shouldEndSession: shouldEndSession
};
};
generateResponse = (sessionAttributes, speechletResponse) => {
return {
version: "1.0",
sessionAttributes: sessionAttributes,
response: speechletResponse
};
};
Et ma sortie console:
START RequestId: 5d4d17a7-0272-11e7-951c-b3d6944457e1 Version: $LATEST
2017-03-06T13:39:47.561Z 5d4d17a7-0272-11e7-951c-b3d6944457e1 Intent Request
2017-03-06T13:39:47.562Z 5d4d17a7-0272-11e7-951c-b3d6944457e1 Then run MySQL code:
END RequestId: 5d4d17a7-0272-11e7-951c-b3d6944457e1
REPORT RequestId: 5d4d17a7-0272-11e7-951c-b3d6944457e1 Duration: 82.48 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 14 MB
Le problème était que je devais mettre mon context.succeed à l'intérieur de mes rappels. Un grand merci à sqlbot, car son discours sur les rappels m'a amené à étudier où les choses mettaient réellement fin à leur exécution.
Donc, apparemment, lorsque vous utilisez AWS Lambda, si le "contexte" se termine avant que vos rappels soient appelés, vous ne recevez pas vos rappels. Donc, même si j'avais placé tous mes rappels comme ceci: connect -> query -> end, le premier rappel de la chaîne de connect n'est jamais appelé parce que "context.succeed" était appelé juste après, ce qui a mis fin à l'exécution.
Voici mon code à partir de maintenant (obtenir une requête appropriée maintenant):
var mysql = require('mysql');
var connection = mysql.createConnection({
...
});
exports.handler = (event, context) => {
try {
if (event.session.new) {
// New Session
console.log("NEW SESSION");
}
switch (event.request.type) {
case "LaunchRequest":
// Launch Request
console.log(`LAUNCH REQUEST`);
context.succeed(
generateResponse({},
buildSpeechletResponse("Welcome to an Alexa Skill, this is running on a deployed lamda function", true)
)
);
break;
case "IntentRequest":
// Intent Request
console.log(`Intent Request`);
console.log('Then run MySQL code:');
connection.connect(function(err) {
console.log('Inside connection.connect() callback');
if (!err) {
console.log("Database is connected ... ");
connection.query("INSERT INTO Users (user_id) VALUES ('TESTNAME')",
function(err, result) {
console.log("Inside connection.query() callback")
if (!err) {
console.log("Query Successful! Ending Connection.");
connection.end();
} else {
console.log("Query error!");
}
});
} else {
console.log("Error connecting database ..." + err.message);
}
context.succeed(
generateResponse({},
buildSpeechletResponse("Welcome to the incredible intelligent MySQLable Alexa!", true)
)
);
});
break;
case "SessionEndedRequest":
// Session Ended Request
console.log(`SESSION ENDED REQUEST`);
break;
default:
context.fail(`INVALID REQUEST TYPE: ${event.request.type}`);
}
} catch (error) {
context.fail(`Exceptiodn: ${error}`)
}
};
//Helpers
buildSpeechletResponse = (outputText, shouldEndSession) => {
return {
outputSpeech: {
type: "PlainText",
text: outputText
},
shouldEndSession: shouldEndSession
};
};
generateResponse = (sessionAttributes, speechletResponse) => {
return {
version: "1.0",
sessionAttributes: sessionAttributes,
response: speechletResponse
};
};