@a1en_yeah

Как организовать promise в NodeJS при запросах к большому числу серверов?

Добрый день,
у меня вызывает затруднение реализация подключения ко множеству серверов.
Код следующий:
Я запрашиваю у одной БД список серверов, и к каждому из серверов я подключаюсь, и спрашиваю список находящихся на них баз данных. Серверов около 400, и полюбому кто то из них или отвечает с ошибкой таймаут, или с ошибкой аутентифициации.
Реализуется это всё через ORM Sequelize, что обязывает далее обрабатывать через .then, а значит через promise.
Подключения к отдельным серверам вложено в другой промис, поэтому при ошибке одного из них, блокирует продолжение, и в итоге внешний промис никогда не заканчивается успешно.
Можете ли подсказать, как можно избежать этого ? Вроде как и промис, а вроде как и всегда отвечает позитивно...
Быть может я ещё плохо понял query в Sequelize... надеюсь что правильно, - docs.sequelizejs.com/en/latest/docs/raw-queries

В данном случае я не получаю списка баз данных в обработчик, через resolve(databases), хотя список кластеров спокойно выводится.
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

    })
};
  • Вопрос задан
  • 1000 просмотров
Решения вопроса 1
Каждый промис обращает внимание только на первый вызов resolve или reject. То есть в вашем случае при проходе по кластерам резолвится только первый. Соответственно каждый кластер требует отдельного промиса, а сам метод должен возвращать общий, который ждёт их окончания:

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 });
			});
	});
}

А так как промисы чейнятся, то можно упростить код:

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 };
		});
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы