Search code examples
javascriptcallbackasync-awaites6-promiseasync.js

await promise before callback in async.each


router.post('/runCommand', async function(req, res){
  let results = [];
  async.each(req.body.requests, async function(request, callback){
    const data = await connect(request.command)
    await results.push(data);
    await callback(null);
  }, function(err){
    if (!err) {
      res.send(202, results)
    }
  })
})

Res.send is never taking place and callback seems to happen before connect is finished running. Connect is succesfully returning a promise because this

router.get('/topics', async function(req, res) {
  console.log('in get');
  const data = await connect(req.body.command);
  await res.send(data);
});

works fine. But including the async.each to run multiple commands seems broken. I know this is an issue with how I'm calling async.each callback function but research hasn't availed how I should be calling it. Is it possible to use a .then() after awaiting a promise?

function connect(command){
  return new Promise(function(resolve) {
  let host = {
        server: {
          host: "host",
          port: "port",
          userName: "user",
          password: config.Devpassword
        },
        commands: [ command ]
      };
  var SSH2Shell = require ('ssh2shell'),
  //Create a new instance passing in the host object
  SSH = new SSH2Shell(host),
  //Use a callback function to process the full session text
  callback = function(sessionText){
    console.log(sessionText)
    resolve(sessionText);
  }
  SSH.connect(callback);
  })
};

Solution

  • While you could continue to sink more time into getting async.each() to work, I recommend just dropping it and going exclusively with the async / await syntax which simplifies your code a lot:

    router.post('/runCommand', async function (req, res) {
      try {
        const results = await Promise.all(
          req.body.requests.map(({ command }) => connect(command))
        );
    
        res.send(202, results);
      } catch ({ message, stack }) {
        res.send(500, { error: message, stack });
      }
    })
    

    Looking at the ssh2shell documentation, I think your connect function could be improved as well for better readability and error handling:

    const SSH2Shell = require('ssh2shell');
    
    function connect (command) {
      return new Promise((resolve, reject) => {
        const host = {
          server: {
            host: 'host',
            port: 'port',
            userName: 'user',
            password: config.Devpassword
          },
          commands: [command]
        };
        //Create a new instance passing in the host object
        const SSH = new SSH2Shell(host);
    
        SSH.on('error', reject);
        SSH.connect(resolve);
      });
    }
    

    Please feel free to comment if this still doesn't work for you.