A
A
a1en_yeah2016-07-15 13:17:47
PostgreSQL
a1en_yeah, 2016-07-15 13:17:47

How to organize a promise in NodeJS when making requests to a large number of servers?

Good afternoon,
I'm having difficulty implementing a connection to multiple servers.
The code is as follows:
I request a list of servers from one database, and I connect to each of the servers and ask for a list of databases located on them. There are about 400 servers, and any one of them either responds with a timeout error, or with an authentication error.
All this is implemented through ORM Sequelize, which obliges further processing through .then, which means through promise.
Connections to separate servers are nested in another promise, so if one of them fails, it blocks the continuation, and as a result, the outer promise never ends successfully.
Can you suggest how this can be avoided? It seems like a promise, but it seems like it always answers positively ...
Maybe I misunderstood the query in Sequelize... I hope it's correct - docs.sequelizejs.com/en/latest/docs/raw-queries
In this case, I don't get the list of databases in the handler, via resolve(databases), although the list of clusters is quietly displayed.

dbAudit.getAllServers = function() {
    return new Promise(function(resolve, reject) {

        //get all clusters
        dbAudit.query(
            'SELECT '
            +   '"FSDN" AS host, '
            +   '"Listen_Port" AS port, '
            +   '"Instance" AS "clusterName", '
            +   '"Version" AS version '
            +'FROM "COLLECTE_POSTGRES"'
        ).then(function(clusters) {
          // resolve(clusters); а вот тут,  кластеры я получаю! 
          var promises  = clusters.forEach(function(cluster) {
                var remote = new Sequelize('postgres', collector.user, collector.password, {host: cluster.host, port: cluster.port, dialect: 'postgres', logging: false});
                remote.query("SELECT datname FROM pg_catalog.pg_database WHERE datname NOT IN ('template0','template1','postgres','repmgr')")
                .then(function(databases) {
                    resolve(databases);
                }, reject)
            })
        },reject);

        //regroup clusters by server

    })
};

Answer the question

In order to leave comments, you need to log in

1 answer(s)
K
Konstantin Gromov, 2016-07-15
@a1en_yeah

Each promise only pays attention to the first call to resolve or reject. That is, in your case, when passing through clusters, only the first one is resolved. Accordingly, each cluster requires a separate promise, and the method itself must return a common one that waits for them to end:

dbAudit.getAllServers = function () {
  return new Promise(function (resolve, reject) {
    dbAudit.query('SELECT "FSDN" AS host, "Listen_Port" AS port, "Instance" AS "clusterName", "Version" AS version FROM "COLLECTE_POSTGRES"')
      .then(function (clusters) {
        var remotesPromises = clusters.map(function (cluster) {
          var remote = new Sequelize('postgres', collector.user, collector.password, {
            host: cluster.host,
            port: cluster.port,
            dialect: 'postgres',
            logging: false
          });

          return getDatabases(remote);
        });

        Promise.all(remotesPromises).then(function (remotes) {
          resolve(remotes);
        });
      }, reject);
  });
};

function getDatabases(remote) {
  return new Promise(function (resolve) {
    remote.query("SELECT datname FROM pg_catalog.pg_database WHERE datname NOT IN ('template0','template1','postgres','repmgr')")
      .then(function (databases) {
        resolve({ status: 'success', databases: databases });
      }, function (error) {
        resolve({ status: 'error', error: error });
      });
  });
}

And since promises are chained, we can simplify the code:
dbAudit.getAllServers = function () {
  return dbAudit.query('SELECT "FSDN" AS host, "Listen_Port" AS port, "Instance" AS "clusterName", "Version" AS version FROM "COLLECTE_POSTGRES"')
    .then(function (clusters) {
      var remotesPromises = clusters.map(function (cluster) {
        var remote = new Sequelize('postgres', collector.user, collector.password, {
          host: cluster.host,
          port: cluster.port,
          dialect: 'postgres',
          logging: false
        });

        return getDatabases(remote);
      });

      return Promise.all(remotesPromises);
    });
};

function getDatabases(remote) {
  return remote.query("SELECT datname FROM pg_catalog.pg_database WHERE datname NOT IN ('template0','template1','postgres','repmgr')")
    .then(function (databases) {
      return { status: 'success', databases: databases };
    }, function (error) {
      return { status: 'error', error: error };
    });
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question