alexa-skills-kit-sdk-for-nodejs: Asynchronous actions not supported?

I’m calling out to an external REST API with the https module, and even wrapping the call in a Promise, a null response is returned by default even if .emit() is not called.

I’m assuming that .execute() calls HandleLambdaEvent() when any handler returns, ending the lambda context. The async code completes a few seconds later, and in the .then() of its promise calls .emit(), but the response has already returned. Am I missing something in the source code that allows a handler to suppress auto response send and manually .emit() when async returns?

This is a really handy module and I’m probably just missing something obvious in my code:

const Alexa = require('alexa-sdk');
const https = require('https');

const handlers = {
    'GoGetRESTfoo': function () {
        console.log("GoGetRESTfoo called");
        promisedRESTrequest('Some foo bar url').then(function(response) {
            console.log("Success!", response); // Yea, REST all the things
            this.emit(':tell', 'ok');
        }, function(error) {
            console.error("Failure!", response); // Boo, bad feels 
            this.emit(':tell', 'Hmm.. that didn\'t work.  Check the CloudWatch Luke.');
        });
    },

    // lots more handlers..
}

exports.handler = (event, context) => {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    console.log('before exec');
    alexa.execute();
    console.log('after exec');
};

Thanks!

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 18

Most upvoted comments

The keyword this is bounded to the last function scope, which is in your case the request callback block.

Instead of writing function (error, response, body) { .. } you should write (error, response, body) => { ... }. This does not re-bind the this-scope, so that this is still the “alexasdk” callback.

Hope this helps you @FerventGeek and @bjm88.

Complete fix for the original issue on top:

const Alexa = require('alexa-sdk');
const https = require('https');

const handlers = {
    'GoGetRESTfoo': function () {
        console.log("GoGetRESTfoo called");
        promisedRESTrequest('Some foo bar url').then((response) => {
            console.log("Success!", response); // Yea, REST all the things
            this.emit(':tell', 'ok');
        }, (error) => {
            console.error("Failure!", response); // Boo, bad feels 
            this.emit(':tell', 'Hmm.. that didn\'t work.  Check the CloudWatch Luke.');
        });
    },

    // lots more handlers..
}

exports.handler = (event, context) => {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

So, for some reason it now started to work for me using Promises. To be honest I do not really know why or what I did (or what I missed before).

Here is an example of a simple Intent that will start my TV through my FHEM server via a Logitech Harmony Hub (it uses a PHP REST API I put in front of FHEM called bridgeAPI).

'activityFernsehen': function () {
    var that=this;
    bridgeAPI.fhemSetFieldValue("WZ.harmony","activity", "Fernsehen")
      .then(function(){  
         that.emit(':tell', utils.getRandomOKResponse());
    }); 
}, 

Can someone try a similar Intent setup using any arbitrary Promise call?

I am having the same issue. Asynchronous actions with callback works, however when using Promises, it does not work. My ‘then’ is never called and when I test using a ‘reject’ I am getting an error about an unhandled promise rejection (even though I have a valid catch there). How do we move forward with this? Should I create a new issue for this since the title of this does not specifically mention promises and async callbacks actually work? I would really like doing alexa skills without callback hell using promises.

I got it to work using async functions. Here is my code

import * as Alexa from 'alexa-sdk'

const handlers = {
    GiveNoteAsync() {
      setTimeout(() => {
        this.emit(':tell', 'Hello Async')
      }, 500)
    },
    GiveNoteSync() {
       this.emit(':tell', "Hello Sync")
    )
}

export function handler(event, context, callback) {
  const alexa = Alexa.handler(event, context)
  alexa.registerHandlers(handlers)
  alexa.execute()
}

I tested this and it worked just fine. Hope this helps.