1

Scenario:

I have a Node.JS 12.x Lambda that is backing an Alexa Skill. The user asks the skill a question, and the search parameter is sent to my Lambda in a slot. I query the SQL DB using the mssql package, then return the result to the user.

Issue:

If I fetch results from the DB, the Lambda executes the query successfully and returns the result, but then the Lambda times out and Alexa seems to have not received the response. If I remove the DB query and just return a string, it all works just fine.

Suspicions:

I think there may be some issue with the async/await stuff in here. I just can't figure out what the issue is though. I have checked my use of async/await several times

If I left anything out just let me know. Thanks in advance!

Code:

/**
 * Intent handler for FindSomething intent
 */
const MyHandler = {
    /**
     * Determine whether this handler is able to process this input
     * @param {Object} handlerInput The input object
     */
    canHandle(handlerInput) {
        // This part works fine
        return util.checkIntentMatch(handlerInput, INTENT_NAME);
    },

    /**
     * Handle the input
     * @param {Object} handlerInput The input object
     */
    async handle(handlerInput) {
        // Extract slot values
        const [
            searchTerm,
        ] = [
            Alexa.getSlotValue(handlerInput.requestEnvelope, 'search_term'),
        ];

        // Fulfill request
        const responseText = await getResponseText(searchTerm);

        // Respond
        return handlerInput.responseBuilder
            .speak(responseText)
            .getResponse();
    },
};

And then getResponseText looks like this:

/**
 * Get the response text for the query
 * @param {string} searchTerm The search term from the user
 */
async function getResponseText(searchTerm) {
    let sectorName = await getSectorForTerm(searchTerm);
    console.log(`Inside getResponseText.  sectorName: ${sectorName}`);

    if (!sectorName) return format(NOT_FOUND_LANGUAGE, { searchTerm });

    return format(FOUND_LANGUAGE, { searchTerm, sectorName });
}

/**
 * Find the sector for a search term
 * @param {string} searchTerm The search term from the user
 */
async function getSectorForTerm(searchTerm) {

    // ========================================================================
    // If I uncomment this line, it works great -- all the way back to the user
    // ========================================================================
    //return 'fake result';

    // Gather prerequisites in parallel
    let [
        query,
        pool
    ] = await Promise.all([
        fs.readFile(path.join(__dirname, 'queries', 'FindQuery.sql'), 'utf8'),
        sql.connect(process.env['connectionString'])
    ]);

    console.log('Pre query');

    // Run query
    let queryResult = await pool.request()
        .input('EntityName', sql.TYPES.VarChar, searchTerm)
        .query(query);

    console.log('Post query');

    // Extract result if any
    let result = undefined;
    if(queryResult.recordset.length > 0) {
        result = queryResult.recordset[0]['SectorName'];
    }

    console.log(`result of getSectorForTerm: ${result}`);

    return result;
}

Edit:

Here is what the log looks like. You can see that the file has loaded, the query has executed, and the return statement is hit within ~500ms. Then several seconds pass before the function times out.

CloudWatch Logs Example

Edit 2:

I have structured my index.js like this example from the AWS docs, so I don't have direct access to context or similar. That can be changed if needed.

enter image description here

trademark
  • 565
  • 4
  • 21

1 Answers1

0

You are using 2 time consuming operations in your skill - file read and sql connection. Probably your skill exceeds 8s timeout. Please check CloudWatch logs related to your skill if there is message like

Task timed out after 8.01 seconds

you should work on some enhancements here. Also make sure that both methods in Promise.all argument return a Promise.

slawciu
  • 775
  • 4
  • 15
  • thanks for your answer. My operations are not taking much time at all. I have verified in the logs that the file is read and the query results are returned within ~500ms of invocation. I have added the log with the timings to my question for clarity. – trademark Jun 25 '20 at 15:35
  • https://stackoverflow.com/a/42627564/2823106 or https://stackoverflow.com/a/58315606/2823106 ? – slawciu Jun 25 '20 at 17:06
  • And the pool, shouldn't you close it? – slawciu Jun 25 '20 at 17:11
  • I thought about that and researched it, and determined that this should work based on 2 reasons: my other lambdas written this way work fine, and the `mssql` docs show example code written this way. I assume that the pool is handled my mssql under the hood. For good measure I tried adding `pool.close()` and similar, but it didn't work still. Also see the addition to my question regarding the `context.success` suggestion – trademark Jun 25 '20 at 17:15
  • Turns out I needed to `await pool.close()`. I forgot that it was a promise. Not sure why my other Lambdas work without explicitly closing the pool (and the example code on their readme doesn't say you need to close it) but that seems to do the trick here for some reason. https://www.npmjs.com/package/mssql#asyncawait – trademark Jun 29 '20 at 14:41