简体   繁体   English

节点 HTTP 请求永远挂起

[英]Node HTTP request hangs forever

We've got a Node.js script that is run once a minute to check the status of our apps.我们有一个每分钟运行一次的 Node.js 脚本来检查我们的应用程序的状态。 Usually, it works just fine.通常,它工作得很好。 If the service is up, it exits with 0. If it's down, it exits with 1. All is well.如果服务已启动,则以 0 退出。如果服务已关闭,则以 1 退出。一切正常。

But every once in a while, it just kinda stops.但每隔一段时间,它就会停止。 The console reports "Calling status API..." and stops there indefinitely.控制台报告“正在调用状态 API...”并无限期地停在那里。 It doesn't even timeout at Node's built-in two-minute timeout.它甚至不会在 Node 内置的两分钟超时时超时。 No errors, nothing.没有错误,什么都没有。 It just sits there, waiting, forever.它只是坐在那里,永远等待。 This is a problem, because it blocks following status check jobs from running.这是一个问题,因为它会阻止以下状态检查作业运行。

At this point, my whole team has looked at it and none of us can figure out what circumstance could make it hang.在这一点上,我的整个团队已经看过它,我们没有人能弄清楚是什么情况可以让它挂起。 We've built in a start-to-finish timeout, so that we can move on to the next job, but that essentially skips a status check and creates blind spots.我们已经建立了一个从开始到结束的超时,以便我们可以继续下一个工作,但这基本上跳过了状态检查并创建了盲点。 So, I open the question to you fine folks.所以,我向你们这些好人提出这个问题。

Here's the script (with names/urls removed):这是脚本(删除了名称/网址):

#!/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);
    }
}

If any of you can see any places where this could possibly hang without output or timeout, that'd be very helpful!如果你们中的任何人都可以看到任何可能在没有输出或超时的情况下挂起的地方,那将非常有帮助!

Thank you, James Tanner谢谢你,詹姆斯·坦纳

EDIT: ps We use https directly, instead of request so that we don't need to do any installation when the script runs.编辑: ps 我们直接使用https ,而不是request这样脚本运行时我们就不需要进行任何安装。 This is because the script can run on any build machine assigned to Jenkins without a custom installation.这是因为该脚本可以在分配给 Jenkins 的任何构建机器上运行,而无需自定义安装。

Inside your response callback your not checking the status..在您的响应回调中,您没有检查状态..

The .on('error', handle_error); .on('error', handle_error); is for errors that occur connecting to the server, status code errors are those that the server responds with after a successful connection.用于连接到服务器时发生的错误,状态码错误是服务器在成功连接后响应的错误。

Normally a 200 status response is what you would expect from a successful request..通常,200 状态响应是您对成功请求的期望。

So a small mod to your http.get to handle this should do..所以你的 http.get 的一个小模块来处理这个应该做..

eg.例如。

https.get(options, function (response) {
  if (response.statusCode != 200) {
    console.log('\tHTTP statusCode not 200:');
    callback(false);
    return; //no point going any further
  }
  ....

Aren't you missing the .end() ?你不是错过了.end()吗?

http.request(options, callback).end()

Something like explained here .这里解释的东西

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM