[英]Batch requests placed via nodejs request.get using rxjs
我目前正在使用以下函數根據調用request.get
的結果創建一個Promise
:
function dlPromiseForMeta(meta) {
return new Promise(function (resolve, reject) {
meta.error = false;
var fileStream = fs.createWriteStream(meta.filePath);
fileStream.on('error', function (error) {
meta.error = true;
console.log('filesystem ' + meta.localFileName + ' ERROR: ' + error);
console.log('record: ' + JSON.stringify(meta));
reject(meta);
});
fileStream.on('close', function () {
resolve(meta);
});
request.get({
uri: meta.url,
rejectUnauthorized: false,
followAllRedirects: true,
pool: {
maxSockets: 1000
},
timeout: 10000,
agent: false
})
.on('socket', function () {
console.log('request ' + meta.localFileName + ' made');
})
.on('error', function (error) {
meta.error = true;
console.log('request ' + meta.localFileName + ' ERROR: ' + error);
console.log('record: ' + JSON.stringify(meta));
reject(meta);
})
.on('end', function () {
console.log('request ' + meta.localFileName + ' finished');
fileStream.close();
})
.pipe(fileStream);
});
}
除非我嘗試多次調用它,否則此方法工作正常,如以下示例所示,其中imagesForKeywords
返回rxjs
Observable
:
imagesForKeywords(keywords, numberOfResults)
.mergeMap(function (meta) {
meta.fileName = path.basename(url.parse(meta.url).pathname);
meta.localFileName = timestamp + '_' + count++ + '_' + meta.keyword + '_' + meta.source + path.extname(meta.fileName);
meta.filePath = path.join(imagesFolder, meta.localFileName);
return rxjs.Observable.fromPromise(dlPromiseForMeta(meta))(meta);
});
當可觀察的源變得足夠大時,我開始收到ESOCKETTIMEDOUT
錯誤。
因此,我想做的是以某種方式批量處理mergeMap
中每個條目(例如100
個條目)發生的事情……所以我並行執行這100 100
條目,然后依次執行每個批處理,然后在最后合並它們。
如何使用rxjs
完成此操作?
我認為最簡單的方法是使用bufferTime()
,它會在一定數量的ms后觸發,但最后還有一個用於計數的參數。
如果存在在合理時間內未達到批處理限制的流模式,使用超時似乎很有用。
如果這不適合您的用例,請用更多詳細信息評論我,我將作相應調整。
您的代碼將如下所示,
imagesForKeywords(keywords, numberOfResults)
.mergeMap(function (meta) {
meta.fileName = path.basename(url.parse(meta.url).pathname);
meta.localFileName = timestamp + '_' + count++ + '_' + meta.keyword + '_' + meta.source + path.extname(meta.fileName);
meta.filePath = path.join(imagesFolder, meta.localFileName);
return meta;
})
.bufferTime(maxTimeout, null, maxBatch)
.mergeMap(items => rxjs.Observable.forkJoin(items.map(dlPromiseForMeta)))
.mergeMap(arr => rxjs.Observable.from(arr))
這是一個可運行的模型,以顯示其工作原理。 已注釋掉最后一個mergeMap
以顯示緩沖。
我已經做了幾件事,
// Some mocking const imagesForKeywords = (keywords, numberOfResults) => { return Rx.Observable.from(keywords.map(keyword => { return {keyword} })) } const dlPromiseForMeta = (meta) => { return Promise.resolve(meta.keyword + '_image') } // Compose meta - looks like it can run at scale, since is just string manipulations. const composeMeta = meta => { // meta.fileName = path.basename(url.parse(meta.url).pathname); // meta.localFileName = timestamp + '_' + count++ + '_' + meta.keyword + '_' + meta.source + path.extname(meta.fileName); // meta.filePath = path.join(imagesFolder, meta.localFileName); return meta; } const maxBatch = 3 const maxTimeout = 50 //ms const bufferedPromises = (keywords, numberOfResults) => imagesForKeywords(keywords, numberOfResults) .map(composeMeta) .bufferTime(maxTimeout, null, maxBatch) .mergeMap(items => Rx.Observable.forkJoin(items.map(dlPromiseForMeta))) //.mergeMap(arr => Rx.Observable.from(arr)) const keywords = ['keyw1', 'keyw2', 'keyw3', 'keyw4', 'keyw5', 'keyw6', 'keyw7']; const numberOfResults = 1; bufferedPromises(keywords, numberOfResults) .subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.