当某些请求可能出错时,我如何可靠地处理数以千计的 HTTP 请求?
how can I reliably process thousands of HTTP requests when some may error?
我之前 运行 遇到过这个问题,因为有几个 HTTP 事务(比如一百个左右的帖子)。今天我正在尝试执行 7k HTTP 请求。这看起来很愚蠢,但这是与目标系统交互的唯一方式。我能做的最好的事情会在大约 96% 的请求完成时停止。然后它将停止并且永远不会完成最后几个请求。
可能我没有正确使用 OiBackoff。它似乎工作正常,但最后 3% 的 GET 永远不会完成。当日志中的最高重试间隔为 40 秒时,我已将其设置为 5 分钟且没有请求返回。
我想知道我是否应该使用 OiBackoff 一次处理 100 个请求以确保它们都已完成。
这里的目标是命中一个 url,其末尾有一个像 CFD1234、CFD1236、CFD1238 这样的数字,并将结果(xml 的小块)推入一个数组。这是代码,最接近我工作的代码。也许我需要尝试不同的图书馆?我已经用 promises 队列试过了,但无法到达 运行。如果我创建一个函数闭包数组并按顺序触发它们,它 将 工作,但它需要永远,比它应该的要长得多。
var cnum, cnums, complete, ld, logger, oibackoff, opt, processHttpGet, request, responses, total, yamljs, _fn, _i, _len;
yamljs = require('yamljs');
request = require('request');
oibackoff = require('oibackoff').backoff({
maxTries: 10,
delayRatio: 10
});
cnums = yamljs.load('./etc/cnumbers.yaml');
responses = [];
logger = {
debug: console.log,
error: console.log
};
ld = require('lodash');
cnums = ld.uniq(cnums);
logger.debug("cnums len: " + cnums.length);
processHttpGet = function(url, opt, cb) {
return request.get(url, opt, function(error, resp, body) {
if (error != null) {
return cb(error, null);
} else if (resp.statusCode >= 400) {
return cb(resp.statusCode, null);
} else {
return cb(null, body);
}
});
};
opt = null;
total = cnums.length;
complete = 0;
_fn = function(CNumber) {
var intermediate, url;
url = "http://abc:def@abc.def.com/xyz/def/abc.asmx/GetValueByID?ID=" + CNumber;
logger.debug("getting " + url);
intermediate = (function(_this) {
return function(err, tries, delay) {
if (err != null) {
logger.debug("GET failed for " + url + ":", err);
logger.debug("tries: %d, delay: %d", tries, delay);
}
if (tries > 10) {
logger.debug("/n/n Failed max tries.");
process.exit(0);
return false;
}
};
})(this);
return oibackoff(processHttpGet, url, opt, intermediate, function(error, response) {
if (error) {
return false;
} else {
++complete;
responses.push(response);
if (complete % 100 === 0) {
console.dir({
url: url,
response: response
});
}
logger.debug("success; responses complete: " + complete + ", total: " + total + ", percentage: " + (ld.round(complete / total, 2) * 100) + "%");
if (complete >= total) {
logger.debug(responses);
return process.exit(0);
}
}
});
};
for (_i = 0, _len = cnums.length; _i < _len; _i++) {
cnum = cnums[_i];
_fn(cnum);
}
对此的答案是使用 Bluebird,Promise.map 和带有退避库的并发。
# coffee
# exports is an array of buffers
retry = (require 'u-promised').retry
Promise = require("bluebird")
# build array of buffers to post
Promise.map(exports, (buffer) ->
f = -> postToEndpoint(buffer)
retry(5, f) # post with up to 5 retries
, {concurrency: config.export.concurrency}) # 40 for my app
.then (result) ->
c = 0
ld.map(result, (x) -> c += x)
msg = "Complete. #{c} posts completed."
logger.info msg
.catch (reason) ->
logger.error reason
我之前 运行 遇到过这个问题,因为有几个 HTTP 事务(比如一百个左右的帖子)。今天我正在尝试执行 7k HTTP 请求。这看起来很愚蠢,但这是与目标系统交互的唯一方式。我能做的最好的事情会在大约 96% 的请求完成时停止。然后它将停止并且永远不会完成最后几个请求。
可能我没有正确使用 OiBackoff。它似乎工作正常,但最后 3% 的 GET 永远不会完成。当日志中的最高重试间隔为 40 秒时,我已将其设置为 5 分钟且没有请求返回。
我想知道我是否应该使用 OiBackoff 一次处理 100 个请求以确保它们都已完成。
这里的目标是命中一个 url,其末尾有一个像 CFD1234、CFD1236、CFD1238 这样的数字,并将结果(xml 的小块)推入一个数组。这是代码,最接近我工作的代码。也许我需要尝试不同的图书馆?我已经用 promises 队列试过了,但无法到达 运行。如果我创建一个函数闭包数组并按顺序触发它们,它 将 工作,但它需要永远,比它应该的要长得多。
var cnum, cnums, complete, ld, logger, oibackoff, opt, processHttpGet, request, responses, total, yamljs, _fn, _i, _len;
yamljs = require('yamljs');
request = require('request');
oibackoff = require('oibackoff').backoff({
maxTries: 10,
delayRatio: 10
});
cnums = yamljs.load('./etc/cnumbers.yaml');
responses = [];
logger = {
debug: console.log,
error: console.log
};
ld = require('lodash');
cnums = ld.uniq(cnums);
logger.debug("cnums len: " + cnums.length);
processHttpGet = function(url, opt, cb) {
return request.get(url, opt, function(error, resp, body) {
if (error != null) {
return cb(error, null);
} else if (resp.statusCode >= 400) {
return cb(resp.statusCode, null);
} else {
return cb(null, body);
}
});
};
opt = null;
total = cnums.length;
complete = 0;
_fn = function(CNumber) {
var intermediate, url;
url = "http://abc:def@abc.def.com/xyz/def/abc.asmx/GetValueByID?ID=" + CNumber;
logger.debug("getting " + url);
intermediate = (function(_this) {
return function(err, tries, delay) {
if (err != null) {
logger.debug("GET failed for " + url + ":", err);
logger.debug("tries: %d, delay: %d", tries, delay);
}
if (tries > 10) {
logger.debug("/n/n Failed max tries.");
process.exit(0);
return false;
}
};
})(this);
return oibackoff(processHttpGet, url, opt, intermediate, function(error, response) {
if (error) {
return false;
} else {
++complete;
responses.push(response);
if (complete % 100 === 0) {
console.dir({
url: url,
response: response
});
}
logger.debug("success; responses complete: " + complete + ", total: " + total + ", percentage: " + (ld.round(complete / total, 2) * 100) + "%");
if (complete >= total) {
logger.debug(responses);
return process.exit(0);
}
}
});
};
for (_i = 0, _len = cnums.length; _i < _len; _i++) {
cnum = cnums[_i];
_fn(cnum);
}
对此的答案是使用 Bluebird,Promise.map 和带有退避库的并发。
# coffee
# exports is an array of buffers
retry = (require 'u-promised').retry
Promise = require("bluebird")
# build array of buffers to post
Promise.map(exports, (buffer) ->
f = -> postToEndpoint(buffer)
retry(5, f) # post with up to 5 retries
, {concurrency: config.export.concurrency}) # 40 for my app
.then (result) ->
c = 0
ld.map(result, (x) -> c += x)
msg = "Complete. #{c} posts completed."
logger.info msg
.catch (reason) ->
logger.error reason