2
votes

I am developing a smart home skill for Alexa. So all requests from Alexa are sent to my AWS Lambda function which then forwards the requests to our servers which contacts the individual smart home devices. So according to the Alexa documentation (https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-response.html#response) I can answer these requests Synchronously, meaning I wait all the way till the operation on the device has completed (while the http connection between the lambda and our servers remain open -> causing charges as lambda is running longer) and send the response via the lambda back to Alexa.

The other option is to answer Asynchronously by sending the answer as a new http request to the Alexa event gateway.

As some operations take some time (considering the way from our servers to the smart home devices, performing the operation, answering etc.) I'd prefer the async method, as it also saves the time on the lambda. I already implemented all the necessary components to answer async but I don't know what I should answer the lambda in case I'll answer async.

My Lambda currently looks somewhat like this:

const https = require('https');

exports.handler = function (request, context) {

    function handleServerRequest(request, context) {

        const doPostRequest = () => {

            const data = request;

            return new Promise((resolve, reject) => {
                const options = {
                    host: 'xxx.ngrok.io',
                    path: '/dyn/alexa/request',
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    }
                };

                /* ... perform https request and resolve promise*/
            });
        };


        doPostRequest().then((response) => {

            log("DEBUG", "Server Response: ", JSON.stringify(response));

            // in case the server decides to answer async (via event gateway) it 
            // immediately answers the https request with a flag "async: true". 

            if(response.async) {
                // -> WHAT TO TELL THE LAMBDA HERE?
                //context.succeed();
                return;
            }
            context.succeed(response);
        });

    }

    handleServerRequest(request, context, "");


When I just do a context.succeed() without a proper response I'll get an error in the Alexa app, telling me "the device is not reacting", followed by indicating the correct status as quickly after that Alexa receives a valid StateReport directive via the event gateway.

How do I properly end the lambda function in case I'll answer asynchronously?

3

3 Answers

2
votes

I contacted Alexa support about this. What I got out of the conversation was that

the documented method of approaching asynchronous responses is to send the asynchronous response before any sort of synchronous response

where "any sort of synchronous response" empirically includes returning null, an empty object or even returning without writing anything at all to the output stream (in the context of a Java 11 Lambda function).

This defeats much of the point of asynchronous responses for me, since the Lambda function cannot fully delegate to the device cloud and return but must wait for it to respond instead. That, or simply sleep until the timeout, hoping the device cloud responds asynchronously before that point.

0
votes

From my experience, you can either send synchronous or asynchronous responses (not both) and this needs to be set up before hand.

To set up asynchronous responses, refer to this doc, which mentions:

On the PERMISSIONS page, slide Send Alexa Events to indicate your skill will send asynchronous responses and/or change report events.

0
votes

I had same problem. I just verified that sending a DeferredResponse synchronously in the handler and POST a asynchronous update to Alexa Event Gateway just later, it works.

I tested with requests for PowerController and PowerLevelController, in the near future I will test other ones.