Alexaが人を返してくれない
DynamoDBからあるスキルに詳しい人の名前を取得してAlexaに返してもらおうとしている。DynamoDBへアクセスはできているが、なぜか人の名前を返してくれず、「さん」しか出てこない。
修正前のソースはこちら。
const SearchSkillHandler = {
canHandle(handlerInput) {
console.log('called SearchSkillHandler.canHandle');
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'SearchSkillIntent';
},
handle(handlerInput) {
const skillsNameValue = getSlotValue(handlerInput.requestEnvelope, 'skills');
console.log('called SearchSkillHandler.handle');
const params = {
TableName: 'skillmap',
KeyConditionExpression: 'skill = :skill',
ExpressionAttributeValues: {
':skill': `${skillsNameValue}`
}
};
let skillsPersonName = '';
documentClient.query(params, (err, data) => {
if (err) {
console.log(JSON.stringify(err, null, 2));
} else {
console.log(JSON.stringify(data, null, 2));
console.log('取得したもの name : ' + data.Items[0].name);
console.log('取得したもの skill : ' + data.Items[0].skill);
skillsPersonName = data.Items[0].name;
console.log('取得したもの skillsPersonName1 : ' + skillsPersonName);
}
});
console.log('取得したもの skillsPersonName2 : ' + skillsPersonName);
return handlerInput.responseBuilder
.speak(`${skillsNameValue}` + "は" + `${skillsPersonName}` + "さんが詳しいです。")
.getResponse();
}
};
ログを追ってみた
困ったときはログ。ということで、CloudWatchのログを見てみました。
よく見てみると、**skillsPersonName2のほうがskillsPersonName1より早くログにでている。**たぶん、DynamoDBからのデータ取得処理は非同期処理なんだろう。
非同期処理という仮説に基づき対応
修正後のソースはこちら。
const SearchSkillHandler = {
canHandle(handlerInput) {
console.log('called SearchSkillHandler.canHandle');
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'SearchSkillIntent';
},
async handle(handlerInput) {
const skillsNameValue = getSlotValue(handlerInput.requestEnvelope, 'skills');
console.log('called SearchSkillHandler.handle');
const params = {
TableName: 'skillmap',
KeyConditionExpression: 'skill = :skill',
ExpressionAttributeValues: {
':skill': `${skillsNameValue}`
}
};
let skillsPersonName = '';
await documentClient.query(params, (err, data) => {
if (err) {
console.log(JSON.stringify(err, null, 2));
} else {
console.log(JSON.stringify(data, null, 2));
console.log('取得したもの name : ' + data.Items[0].name);
console.log('取得したもの skill : ' + data.Items[0].skill);
skillsPersonName = data.Items[0].name;
console.log('取得したもの skillsPersonName1 : ' + skillsPersonName);
}
}).promise();
console.log('取得したもの skillsPersonName2 : ' + skillsPersonName);
return handlerInput.responseBuilder
.speak(`${skillsNameValue}` + "は" + `${skillsPersonName}` + "さんが詳しいです。")
.getResponse();
}
};
handleの関数にasyncをつけたのと、documentClient.queryにawaitとpromiseをつけて同期処理にしました。