使用 NodeJS+request-promise 的同时请求太多
Too many simultaneous requests with NodeJS+request-promise
我有一个包含 URLs 的大数组(大约 9000 个元素)的 NodeJS 项目。将使用 request-promise
包请求那些 URL。但是,同一个客户端对同一个网站的 9000 个并发 GET 请求,服务器和客户端都不喜欢,所以我想随着时间的推移分散它们。我环顾四周,发现 Promise.map
与 {concurrency: int}
选项 here 一起,听起来它可以满足我的要求。但我无法让它工作。我的代码如下所示:
const rp = require('request-promise');
var MongoClient = require('mongodb').MongoClient;
var URLarray = []; //This contains 9000 URLs
function getWebsite(url) {
rp(url)
.then(html => { /* Do some stuff */ })
.catch(err => { console.log(err) });
}
MongoClient.connect('mongodb://localhost:27017/some-database', function (err, client) {
Promise.map(URLArray, (url) => {
db.collection("some-collection").findOne({URL: url}, (err, data) => {
if (err) throw err;
getWebsite(url, (result) => {
if(result != null) {
console.log(result);
}
});
}, {concurrency: 1});
});
我想我可能误解了如何处理承诺。在这种情况下,我会认为,将并发选项设置为 1,数组中的每个 URL 将依次用于数据库搜索,然后作为参数传递给 getWebsite
,其结果将显示在其回调函数中。 THEN 将处理数组中的下一个元素。
实际发生的是 URL 中的一些(可能是 10 个)被正确提取,然后服务器开始偶尔响应 500 内部服务器错误。几秒钟后,我的电脑死机然后重新启动(我猜这是由于某种恐慌?)。
我该如何解决这个问题?
如果问题确实与并发有关,您可以将工作分成块并将块链接起来。
让我们从执行 mongo 查找和获取....
的函数开始
// answer a promise that resolves to data from mongo and a get from the web
// for a given a url, return { mongoResult, webResult }
// (assuming this is what OP wants. the OP appears to discard the mongo result)
//
function lookupAndGet(url) {
// use the promise-returning variant of findOne
let result = {}
return db.collection("some-collection").findOne({URL: url}).then(mongoData => {
result.mongoData = mongoData
return rp(url)
}).then(webData => {
result.webData = webData
return result
})
}
lodash and underscore 都提供了一种分块方法,可以将数组分成更小的数组。自己编写或使用他们的。
const _ = require('lodash')
let chunks = _.chunk(URLArray, 5) // say 5 is a reasonable concurrency
这是答案的要点,制作一个块链,这样你只能同时执行较小的尺寸...
let chain = chunks.reduce((acc, chunk) => {
const chunkPromise = Promise.all(chunk.map(url => lookupAndGet(url)))
return acc.then(chunkPromise)
}, Promise.resolve())
现在执行链。块承诺将 return 块大小的结果数组,因此您的缩减结果将是一个数组数组。幸运的是,lodash 和 underscore 都有一个方法来“展平”嵌套数组。
// turn [ url, url, ...] into [ { mongoResult, webResult }, { mongoResult, webResult }, ...]
// running only 5 requests at a time
chain.then(result => {
console.log(_.flatten(result))
})
我有一个包含 URLs 的大数组(大约 9000 个元素)的 NodeJS 项目。将使用 request-promise
包请求那些 URL。但是,同一个客户端对同一个网站的 9000 个并发 GET 请求,服务器和客户端都不喜欢,所以我想随着时间的推移分散它们。我环顾四周,发现 Promise.map
与 {concurrency: int}
选项 here 一起,听起来它可以满足我的要求。但我无法让它工作。我的代码如下所示:
const rp = require('request-promise');
var MongoClient = require('mongodb').MongoClient;
var URLarray = []; //This contains 9000 URLs
function getWebsite(url) {
rp(url)
.then(html => { /* Do some stuff */ })
.catch(err => { console.log(err) });
}
MongoClient.connect('mongodb://localhost:27017/some-database', function (err, client) {
Promise.map(URLArray, (url) => {
db.collection("some-collection").findOne({URL: url}, (err, data) => {
if (err) throw err;
getWebsite(url, (result) => {
if(result != null) {
console.log(result);
}
});
}, {concurrency: 1});
});
我想我可能误解了如何处理承诺。在这种情况下,我会认为,将并发选项设置为 1,数组中的每个 URL 将依次用于数据库搜索,然后作为参数传递给 getWebsite
,其结果将显示在其回调函数中。 THEN 将处理数组中的下一个元素。
实际发生的是 URL 中的一些(可能是 10 个)被正确提取,然后服务器开始偶尔响应 500 内部服务器错误。几秒钟后,我的电脑死机然后重新启动(我猜这是由于某种恐慌?)。
我该如何解决这个问题?
如果问题确实与并发有关,您可以将工作分成块并将块链接起来。
让我们从执行 mongo 查找和获取....
的函数开始// answer a promise that resolves to data from mongo and a get from the web
// for a given a url, return { mongoResult, webResult }
// (assuming this is what OP wants. the OP appears to discard the mongo result)
//
function lookupAndGet(url) {
// use the promise-returning variant of findOne
let result = {}
return db.collection("some-collection").findOne({URL: url}).then(mongoData => {
result.mongoData = mongoData
return rp(url)
}).then(webData => {
result.webData = webData
return result
})
}
lodash and underscore 都提供了一种分块方法,可以将数组分成更小的数组。自己编写或使用他们的。
const _ = require('lodash')
let chunks = _.chunk(URLArray, 5) // say 5 is a reasonable concurrency
这是答案的要点,制作一个块链,这样你只能同时执行较小的尺寸...
let chain = chunks.reduce((acc, chunk) => {
const chunkPromise = Promise.all(chunk.map(url => lookupAndGet(url)))
return acc.then(chunkPromise)
}, Promise.resolve())
现在执行链。块承诺将 return 块大小的结果数组,因此您的缩减结果将是一个数组数组。幸运的是,lodash 和 underscore 都有一个方法来“展平”嵌套数组。
// turn [ url, url, ...] into [ { mongoResult, webResult }, { mongoResult, webResult }, ...]
// running only 5 requests at a time
chain.then(result => {
console.log(_.flatten(result))
})