isaac.hazan
isaac.hazan

Reputation: 3874

NodeJS Create an array of functions and execute it through async.series

Starting my learning curve on NodeJS, I am trying to call a sequence of functions using async.series. Each function is a command line that is called remotely using REST.

function TestStorageDeviceBasic()
{
    scenario = [
        'cmdline1',
        'cmdline2'
    ];

    tasks = [];
    scenario.forEach(command => { tasks.push(RunCommand(sessionId,command));});
    async.series(tasks);
}

function RunCommand(sessionId, cmdLine)
{
    var options = {
        uri: `http://${domain}/api/v1/commands`,
        method: 'POST',
        json: {
            'session-id' : `${sessionId}`,
            'command-line': `${cmdLine}` 
        }
      };

      request(options, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            log.debug(`\"${cmdLine}\" status code successful`)
            log.debug(body);
        }
        else
            log.error(`\"${cmdLine}\" status code failed`,error);
      });
}

I am getting a few problems even though the RunCommand function seems to be called.

(node:21008) UnhandledPromiseRejectionWarning: Error: expected a function
    at wrapAsync (C:\work\MyJavascriptProject\my_sample\node_modules\async\dist\async.js:198:50)
    at C:\work\MyJavascriptProject\my_sample\node_modules\async\dist\async.js:2952:13

Why RunCommand is not considered a function?

Upvotes: 1

Views: 529

Answers (2)

Ashish Modi
Ashish Modi

Reputation: 7770

There are three things you need to modify in the code

  • Wrap the RunCommand in a function and then push it in tasks array
  • Make sure you pass callback while wrapping up
  • Modify the RunCommand to have a callback as well so that async.series can use the output from the callbacks.

Since you are not passing callback for your RunCommand, it is only getting executed once as async.series doesn't know when to proceed ahead. The modified code would look like

function TestStorageDeviceBasic() {
  scenario = ["cmdline1", "cmdline2"];

  tasks = [];
  scenario.forEach(command => {
    tasks.push(callack => RunCommand(sessionId, command, callack));
  });
  async.series(tasks, (err, data) => {
    if (err) {
      console.error(err);
    }
    console.log(data);
  });
}

function RunCommand(sessionId, cmdLine, callack) {
  var options = {
    uri: `http://${domain}/api/v1/commands`,
    method: "POST",
    json: {
      "session-id": `${sessionId}`,
      "command-line": `${cmdLine}`
    }
  };

  request(options, function(error, response, body) {
    if (!error && response.statusCode == 200) {
      log.debug(`\"${cmdLine}\" status code successful`);
      log.debug(body);
      callack(null, body);
    } else {
      log.error(`\"${cmdLine}\" status code failed`, error);
      callack(error, null);
    }
  });
}

Hope this helps

Upvotes: 1

JohnnyHK
JohnnyHK

Reputation: 311835

It's because you're calling RunCommand and then pushing its return value into tasks. Instead, push a function that makes the call:

scenario.forEach(command => { 
    tasks.push(() => RunCommand(sessionId,command));
});

Upvotes: 1

Related Questions