使用Node限制对第3部分Apis的请求 [英] Throttling requests to 3rd part Apis with Node

查看:107
本文介绍了使用Node限制对第3部分Apis的请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我正在构建一个空间地图并将关系转换为mongodb。在这个场景中,我有地区,星座和太阳系。其中1个区域可以有许多星座,每个星座可以有许多太阳系。我有一个api允许抓取其中的一些,但它需要每个项目api调用。提出我正在制作~6000 api电话的问题。



继承第三方的api标准:




  • 一般费率限制:150个请求每秒

  • 突发大小:400

  • 并发连接数:20



这是我的数据库模型:



地区型号:

  var mongoose = require('mongoose'); 
var Schema = mongoose.Schema;

//模式定义
var regionSchema = new Schema({
_id:Number,
name:String,
description:String,
href:String,
constellations:[{
type:Schema.ObjectId,
ref:'Constellation'
}] //参考
});

//公开(导出)模型
module.exports = mongoose.model('Region',regionSchema);

Constellation Model:

  var mongoose = require('mongoose'); 
var Schema = mongoose.Schema;

//模式定义
var constellationSchema = new Schema({
_id:Number,
name:String,
href:String,
solarSystems:[{
类型:Schema.ObjectId,
ref:'SolarSystem'
}]
});

//公开(导出)模型
module.exports = mongoose.model('Constellation',constellationSchema);

太阳系模型:

  var mongoose = require('mongoose'); 
var Schema = mongoose.Schema;

//架构定义
var solarSystemSchema = new Schema({
_id:Number,
name:String,
imgUrl:String
});

//公开(导出)模型
module.exports = mongoose.model('SolarSystem',solarSystemSchema);

我也试图以正确的顺序保存它们,以便为关系填充引用。这是我的代码:

  function getAllRegions(req,res) {
getAllRegionsHrefs()。then(function(hrefs){
var newRegions = [];
for(var href in hrefs){
var options = {
uri:hrefs [href],
json:true
};
RequestPromise(options).then(function(responseItem){
var constellationObjects = [];
for(responseItem.constellations中的var项目){
var newConstellation = constellationModel({
_id:responseItem.constellations [item] .id,
href:'https://getspaceInfoHere.com/ constellations /'+ responseItem.constellations [item] .id +'/'
});
newConstellation.sav e();
constellationObjects.push(newConstellation);
}
var newRegion = regionModel({
_id:responseItem.id,
name:responseItem.name,
description:responseItem.description,
href :'https://getspaceInfoHere.com/regions/'+responseItem.id+'/',
constellations:constellationObjects
});
newRegion.save();
newRegions.push(newRegion);
console.log(newRegion);
});
}
});
}

函数getAllRegionsHrefs(){
var options = {
uri:universeInfoEndpoint,
json:true
};
返回RequestPromise(options).then(function(responseItems){
var regionHrefs = [];
for(var item in responseItems.items){
regionHrefs.push(responseItems) .items [item] .href);
}
返回regionHrefs;
});
}

现在我甚至都没有尝试获取提供系统的详细星座信息info(然后提供一个href来获取详细的系统信息)并且我遇到了我的最大值。限制这个的最佳方法是什么,以便我可以保持在参数范围内?



UPDATE



  function getAllRegions(req,res){
getAllRegionsHrefs()。then(function(hrefs){
var chunks = _.chunk(hrefs,25);
返回Promise.map(块,函数(块){
return Promise.map(chunk,getRegion).then(function(getRegionResults){
for(get item in getRegionResults){
Promise.map(getRegionResults [item] .constellations,getConstellationInfo).then(function( constellationInfo){
var chunks = _.chunk(constellationInfo,150);
返回Promise.map(块,函数(块){
返回Promise.map(chunk,getSystem).delay (20000);
})
})。延迟(20000);
}
})。延迟(200000);
});
});
}

函数getSystem(系统){
for(系统中的var updateSystem){
var options = {
uri:systems [updateSystem]。 href,
json:true
};
RequestPromise(options).then(function(responseItem){
//抓住数据库中的系统并使用其信息更新它
systemModel.findOne({_ id:systems [updateSystem]。 _id},function(err,doc){
doc.name = responseItem.name;
doc.save();
});

});
}
}

函数getConstellationInfo(constellation){
var options = {
uri:constellation.href,
json:true
};
返回RequestPromise(options).then(function(responseItem){
var arrayOfSystems = [];
for(var system in responseItem.systems){
var newSystem = new systemModel ({
_id:responseItem.systems [system] .id,
href:responseItem.systems [system] .href
});
newSystem.save();
arrayOfSystems.push(newSystem);
}
//找到星座并用它的信息更新它
constellationModel.findOne({_ id:constellation._id},function(err,doc ){
doc.name = responseItem.name;
doc.solarSystems = arrayOfSystems;
doc.save();
});
返回arrayOfSystems;
});
}


函数getRegion(href){
var options = {
uri:href,
json:true
};
返回RequestPromise(options).then(function(responseItem){
var constellationObjects = [];
for(var item in responseItem.constellations){
var newConstellation = constellationModel( {
_id:responseItem.constellations [item] .id,
href:eveConstellationCrestEndpoint + responseItem.constellations [item] .id +'/'
});
newConstellation.save( );
constellationObjects.push(newConstellation);
}
var newRegion = regionModel({
_id:responseItem.id,
name:responseItem.name,
description:responseItem.description,
href:universeEndpoint + responseItem.id +'/',
constellations:constellationObjects
});
newRegion.save();
返回newRegion;
});
}

函数getAllRegionsHrefs(){
var options = {
uri:universeEndpoint,
json:true
};
返回RequestPromise(options).then(function(responseItems){
var regionHrefs = [];
for(var item in responseItems.items){
regionHrefs.push(responseItems) .items [item] .href);
}
返回regionHrefs;
});
}

现在这适用于整个链(获取区域,星座和系统信息)但超时工作正在开始拒绝系统级别的连接。任何建议?

解决方案

你可以通过将你的href分成20组并在每个块之后设置延迟来达到这个目的,你可能想要使用这些参数:



使用lodash的 _。chunk 和Bluebird的 Promise.delay > Promise.map

  function getAllRegions(req,res){
getAllRegionsHrefs()。then(function(hrefs){
var chunks = _.chunk(hrefs,20);
返回Promise.map(块,函数(块){
/ /将延迟调整为你所需要的
//它将等待延迟(以ms为单位),然后开始下一个请求块
返回Promise.map(chunk,getRegion).delay(150000) );
});
});
}

函数getRegion(href){
var options = {
uri:hrefs [href],
json:true
} ;
返回RequestPromise(options).then(function(responseItem){
var constellationObjects = [];
for(var item in responseItem.constellations){
var newConstellation = constellationModel( {
_id:responseItem.constellations [item] .id,
href:'https://getspaceInfoHere.com/constellations/'+responseItem.constellations[item].id+'/'
});
newConstellation.save();
constellationObjects.push(newConstellation);
}
var newRegion = regionModel({
_id:responseItem.id,
name:responseItem.name,
description:responseItem.description,
href:'https://getspaceInfoHere.com/regions/'+responseItem.id+'/',
constellations :constellationObjects
});
newRegion.save();
console.log(newRegion);
返回newRegio n;
});
}


So I am building a space map and dumping the relations into a mongodb. In thiscenario I have regions, constellations, and solar system. Where 1 region can have many constellations and each constellation can have many solar systems. I have an api that allows crawl some of this but it requires an api call per item. Bringing up the problem where I am making ~6000 api calls.

Heres the 3rd party's api criteria:

  • General Rate Limit: 150 requests per second
  • Burst Size: 400
  • Concurrent Connections: 20

Here is my db models:

Region Model:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

//Schema Definition
var regionSchema = new Schema({
    _id: Number,
    name: String,
    description: String,
    href: String,
    constellations: [{
        type: Schema.ObjectId,
        ref: 'Constellation'
    }]//Reference
});

//Expose (export) the model
module.exports = mongoose.model('Region', regionSchema);

Constellation Model:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

//Schema Definition
var constellationSchema = new Schema({
    _id: Number,
    name: String,
    href: String,
    solarSystems: [{
        type: Schema.ObjectId,
        ref: 'SolarSystem'
    }]
});

//Expose (export) the model
module.exports = mongoose.model('Constellation', constellationSchema);

Solar System Model:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

//Schema Definition
var solarSystemSchema = new Schema({
    _id: Number,
    name: String,
    imgUrl: String
});

//Expose (export) the model
module.exports = mongoose.model('SolarSystem', solarSystemSchema);

I am also trying to save them in the proper order so the references are populated for the relations.

Here is my code:

function getAllRegions(req, res){
   getAllRegionsHrefs().then(function (hrefs){
       var newRegions = [];
       for(var href in hrefs){
           var options = {
               uri: hrefs[href],
               json: true
           };
           RequestPromise(options).then(function (responseItem){
               var constellationObjects = [];
               for(var item in responseItem.constellations){
                   var newConstellation = constellationModel({
                       _id: responseItem.constellations[item].id,
                       href: 'https://getspaceInfoHere.com/constellations/'+responseItem.constellations[item].id+'/'
                   });
                   newConstellation.save();
                   constellationObjects.push(newConstellation);
               }
               var newRegion = regionModel({
                   _id: responseItem.id,
                   name: responseItem.name,
                   description: responseItem.description,
                   href: 'https://getspaceInfoHere.com/regions/'+responseItem.id+'/',
                   constellations: constellationObjects
               });
               newRegion.save();
               newRegions.push(newRegion);
               console.log(newRegion);
           });
       }
   });
}

function getAllRegionsHrefs(){
    var options = {
        uri: universeInfoEndpoint,
        json: true
    };
   return RequestPromise(options).then(function (responseItems){
        var regionHrefs = [];
        for(var item in responseItems.items){
                regionHrefs.push(responseItems.items[item].href);
        }
        return regionHrefs;
    });
}

Now I am not even trying to get the detailed constellation info which provides the system info (which then provides an href to get detailed system info) and I'm running into my max. What are the best ways to throttle this so I can stay within the parameters?

UPDATE

function getAllRegions(req, res){
    getAllRegionsHrefs().then(function (hrefs){
        var chunks = _.chunk(hrefs, 25);
        return Promise.map(chunks, function(chunk) {
            return Promise.map(chunk, getRegion).then(function (getRegionResults){
                for(var item in getRegionResults) {
                    Promise.map(getRegionResults[item].constellations, getConstellationInfo).then(function (constellationInfo) {
                        var chunks = _.chunk(constellationInfo, 150);
                        return Promise.map(chunks, function (chunk) {
                            return Promise.map(chunk, getSystem).delay(20000);
                        })
                    }).delay(20000);
                }
            }).delay(200000);
        });
    });
}

function getSystem(systems){
    for(var updateSystem in systems){
        var options = {
            uri: systems[updateSystem].href,
            json: true
        };
         RequestPromise(options).then(function (responseItem){
             //Grab the system in the db and update it with its info
            systemModel.findOne({ _id: systems[updateSystem]._id }, function (err, doc){
                doc.name = responseItem.name;
                doc.save();
            });

        });
    }
}

function getConstellationInfo(constellation) {
    var options = {
        uri: constellation.href,
        json: true
    };
    return RequestPromise(options).then(function (responseItem){
        var arrayOfSystems = [];
        for(var system in responseItem.systems){
            var newSystem = new systemModel({
                _id: responseItem.systems[system].id,
                href: responseItem.systems[system].href
            });
            newSystem.save();
            arrayOfSystems.push(newSystem);
        }
        //find the constellation and update it with its info
        constellationModel.findOne({ _id: constellation._id }, function (err, doc){
            doc.name = responseItem.name;
            doc.solarSystems = arrayOfSystems;
            doc.save();
        });
        return arrayOfSystems;
    });
}


function getRegion(href) {
    var options = {
        uri: href,
        json: true
    };
    return RequestPromise(options).then(function (responseItem){
        var constellationObjects = [];
        for(var item in responseItem.constellations){
            var newConstellation = constellationModel({
                _id: responseItem.constellations[item].id,
                href: eveConstellationCrestEndpoint + responseItem.constellations[item].id+'/'
            });
            newConstellation.save();
            constellationObjects.push(newConstellation);
        }
        var newRegion = regionModel({
            _id: responseItem.id,
            name: responseItem.name,
            description: responseItem.description,
            href: universeEndpoint + responseItem.id+'/',
            constellations: constellationObjects
        });
        newRegion.save();
        return newRegion;
    });
}

function getAllRegionsHrefs(){
    var options = {
        uri: universeEndpoint,
        json: true
    };
   return RequestPromise(options).then(function (responseItems){
        var regionHrefs = [];
        for(var item in responseItems.items){
                regionHrefs.push(responseItems.items[item].href);
        }
        return regionHrefs;
    });
}

Right now this is working for the entire chain(gets region, constellation, and system info) but the timeouts are working and starts to refuse connections at the system level. Any advice?

解决方案

You can achieve this by chunking your hrefs into sets of 20 and setting a delay after each chunk, you'll probably want to play with those parameters:

Using lodash's _.chunk and Bluebird's Promise.delay with Promise.map:

function getAllRegions(req, res){
   getAllRegionsHrefs().then(function (hrefs){
       var chunks = _.chunk(hrefs, 20);
       return Promise.map(chunks, function(chunk) {
         // tune the delay to what you need it to be
         // it will wait the delay (in ms) before starting the next chunk of requests
         return Promise.map(chunk, getRegion).delay(150000);
       });
   });
}

function getRegion(href) {
    var options = {
        uri: hrefs[href],
        json: true
    };
    return RequestPromise(options).then(function (responseItem){
        var constellationObjects = [];
        for(var item in responseItem.constellations){
            var newConstellation = constellationModel({
                _id: responseItem.constellations[item].id,
                href: 'https://getspaceInfoHere.com/constellations/'+responseItem.constellations[item].id+'/'
            });
            newConstellation.save();
            constellationObjects.push(newConstellation);
        }
        var newRegion = regionModel({
            _id: responseItem.id,
            name: responseItem.name,
            description: responseItem.description,
            href: 'https://getspaceInfoHere.com/regions/'+responseItem.id+'/',
            constellations: constellationObjects
        });
        newRegion.save();
        console.log(newRegion);
        return newRegion;
    });
}

这篇关于使用Node限制对第3部分Apis的请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆