Javascript 节点HTTP请求永远挂起
我们有一个Node.js脚本,每分钟运行一次以检查应用程序的状态。通常,它工作得很好。如果服务已启动,则它将以0退出。如果它关闭,它将以1退出。一切都很好 但每隔一段时间,它就会停止。控制台报告“调用状态API…”并无限期地停止。它甚至不会在节点内置的两分钟超时时超时。没有错误,什么都没有。它只是坐在那里,等待,永远。这是一个问题,因为它会阻止以下状态检查作业的运行 在这一点上,我的整个团队都看到了这一点,没有人能弄清楚是什么情况导致了这一点。我们已经建立了一个从开始到结束的超时,这样我们就可以继续下一个作业,但这实际上跳过了状态检查,并造成了盲点。所以,我向各位提出这个问题 以下是脚本(已删除名称/URL):Javascript 节点HTTP请求永远挂起,javascript,node.js,http,request,Javascript,Node.js,Http,Request,我们有一个Node.js脚本,每分钟运行一次以检查应用程序的状态。通常,它工作得很好。如果服务已启动,则它将以0退出。如果它关闭,它将以1退出。一切都很好 但每隔一段时间,它就会停止。控制台报告“调用状态API…”并无限期地停止。它甚至不会在节点内置的两分钟超时时超时。没有错误,什么都没有。它只是坐在那里,等待,永远。这是一个问题,因为它会阻止以下状态检查作业的运行 在这一点上,我的整个团队都看到了这一点,没有人能弄清楚是什么情况导致了这一点。我们已经建立了一个从开始到结束的超时,这样我们就可以
#/usr/bin/env节点
//设置:-------------------------------------------------------------------------------------------------
/**联系状态信息的URL*/
const STATUS_API=process.env.STATUS_API;
/**在报告为失败之前尝试进行的次数*/
常量尝试_限制=3;
/**开始另一次尝试之前等待的时间量,以毫秒为单位*/
持续尝试延迟=5000;
//运行时:--------------------------------------------------------------------------------------------------
const URL=require('URL');
常量https=require('https');
//做第一次尝试。
尝试(1,状态API);
//职能:------------------------------------------------------------------------------------------------
函数进行尝试(尝试次数、url){
console.log('\n\n连接尝试:',尝试编号);
检查_状态(url、功能(成功){
console.log('\n尝试',成功?'PASSED':'FAILED');
//如果此尝试成功,请报告成功。
如果(成功){
日志(“\n状态检查在”“尝试次数”“尝试之后通过”);
进程退出(0);
}
//否则,如果有其他尝试,请重试。
否则如果(尝试次数<尝试次数限制){
setTimeout(make_-trunt.bind(null,trunt_-number+1,url),trunt_-DELAY);
}
//否则,我们将无法尝试。报告失败。
否则{
console.log(“\n状态检查失败”);
过程。退出(1);
}
})
}
函数检查\u状态(url、回调){
变量句柄\错误=函数(错误){
console.log(“\t失败。\n”);
console.log('\t'+error.toString().replace(/\n\r?/g,'\n\t'));
回调(假);
};
console.log(“\t调用状态API…”);
试一试{
var options=URL.parse(URL);
options.timeout=20000;
https.get(选项、函数(响应){
变量体=“”;
response.setEncoding('utf8');
on('data',函数(data){body+=data;});
response.on('end',function(){
console.log(“\t已连接。\n”);
试一试{
var parsed=JSON.parse(body);
if((!parsed.started | |!parsed.uptime)){
log('\t收到意外的JSON响应:');
console.log('\t\t'+JSON.stringify(已解析,null,1).replace(/\n\r?/g,'\n\t\t'));
回调(假);
}
否则{
log('\t从API接收的状态详细信息:');
console.log('\t\t服务器已启动:',已解析。已启动);
console.log('\t\t服务器正常运行时间:',已解析.uptime);
回调(true);
}
}
捕获(错误){
log('\t收到意外的非JSON响应:');
console.log('\t\t'+body.trim().replace(/\n\r?/g,'\n\t\t'));
回调(假);
}
});
}).on('error',handle_error);
}
捕获(错误){
处理错误(错误);
}
}
如果你们中的任何一个人可以看到任何地方,在没有输出或超时的情况下,这可能会挂起,这将非常有帮助
谢谢,,
詹姆斯·坦纳
EDIT:p.s.我们直接使用
https
,而不是request
,因此在脚本运行时不需要进行任何安装。这是因为脚本可以在分配给Jenkins的任何生成计算机上运行,而无需自定义安装。在响应回调中,您没有检查状态
.on('error',handle\u error)代码>用于连接到服务器时发生的错误,状态代码错误是服务器在成功连接后响应的错误
通常情况下,200状态响应是成功请求的预期结果
因此,对http.get进行一个小的修改来处理这个问题就可以了
例如
您是否缺少.end()
http.request(选项,回调).end()
类似于解释。我会检查您的响应回调中的状态代码,如果它不等于200,则引发错误。哦,对不起@Keith,我想我不清楚这一点。成功取决于反应。200码不一定足够。编辑了我的评论。在我完成输入之前,我已经点击了“添加”。我并不是说200就足够了,你仍然需要检查状态响应,你可能会得到一个503服务不可用
或其他什么。因此,您仍然会收到响应,但不会收到任何数据
或结束
事件,因此将挂起,因为您永远不会结束呼叫回调。老实说,您离此不远,我将发布一个带有额外检查的小片段。哦,刚刚注意到你找到了一个链接,是的。。实施额外的检查,你应该对g很好
#!/usr/bin/env node
// SETTINGS: -------------------------------------------------------------------------------------------------
/** URL to contact for status information. */
const STATUS_API = process.env.STATUS_API;
/** Number of attempts to make before reporting as a failure. */
const ATTEMPT_LIMIT = 3;
/** Amount of time to wait before starting another attempt, in milliseconds. */
const ATTEMPT_DELAY = 5000;
// RUNTIME: --------------------------------------------------------------------------------------------------
const URL = require('url');
const https = require('https');
// Make the first attempt.
make_attempt(1, STATUS_API);
// FUNCTIONS: ------------------------------------------------------------------------------------------------
function make_attempt(attempt_number, url) {
console.log('\n\nCONNECTION ATTEMPT:', attempt_number);
check_status(url, function (success) {
console.log('\nAttempt', success ? 'PASSED' : 'FAILED');
// If this attempt succeeded, report success.
if (success) {
console.log('\nSTATUS CHECK PASSED after', attempt_number, 'attempt(s).');
process.exit(0);
}
// Otherwise, if we have additional attempts, try again.
else if (attempt_number < ATTEMPT_LIMIT) {
setTimeout(make_attempt.bind(null, attempt_number + 1, url), ATTEMPT_DELAY);
}
// Otherwise, we're out of attempts. Report failure.
else {
console.log("\nSTATUS CHECK FAILED");
process.exit(1);
}
})
}
function check_status(url, callback) {
var handle_error = function (error) {
console.log("\tFailed.\n");
console.log('\t' + error.toString().replace(/\n\r?/g, '\n\t'));
callback(false);
};
console.log("\tCalling status API...");
try {
var options = URL.parse(url);
options.timeout = 20000;
https.get(options, function (response) {
var body = '';
response.setEncoding('utf8');
response.on('data', function (data) {body += data;});
response.on('end', function () {
console.log("\tConnected.\n");
try {
var parsed = JSON.parse(body);
if ((!parsed.started || !parsed.uptime)) {
console.log('\tReceived unexpected JSON response:');
console.log('\t\t' + JSON.stringify(parsed, null, 1).replace(/\n\r?/g, '\n\t\t'));
callback(false);
}
else {
console.log('\tReceived status details from API:');
console.log('\t\tServer started:', parsed.started);
console.log('\t\tServer uptime:', parsed.uptime);
callback(true);
}
}
catch (error) {
console.log('\tReceived unexpected non-JSON response:');
console.log('\t\t' + body.trim().replace(/\n\r?/g, '\n\t\t'));
callback(false);
}
});
}).on('error', handle_error);
}
catch (error) {
handle_error(error);
}
}
https.get(options, function (response) {
if (response.statusCode != 200) {
console.log('\tHTTP statusCode not 200:');
callback(false);
return; //no point going any further
}
....