【问题标题】:Node HTTP request hangs forever节点 HTTP 请求永远挂起
【发布时间】:2020-12-06 16:52:57
【问题描述】:

我们有一个 Node.js 脚本,它每分钟运行一次来​​检查我们的应用程序的状态。通常,它工作得很好。如果服务启动,则以 0 退出。如果服务停止,则以 1 退出。一切正常。

但每隔一段时间,它就会停止。控制台报告“调用状态 API ...”并无限期地停在那里。它甚至不会在 Node 的内置两分钟超时中超时。没有错误,什么都没有。它只是坐在那里,等待,永远。这是一个问题,因为它会阻止运行以下状态检查作业。

在这一点上,我的整个团队都看过它,但我们谁都无法弄清楚是什么情况会导致它挂起。我们已经建立了一个从开始到完成的超时,这样我们就可以继续下一个工作,但这实际上会跳过状态检查并产生盲点。所以,我向各位好人提出问题。

这是脚本(删除了名称/网址):

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

如果你们中的任何人都可以看到任何可能在没有输出或超时的情况下挂起的地方,那将非常有帮助!

谢谢你, 詹姆斯·坦纳

编辑: p.s.我们直接使用https,而不是request,这样我们在脚本运行时就不需要进行任何安装。这是因为脚本可以在分配给 Jenkins 的任何构建机器上运行,无需自定义安装。

【问题讨论】:

  • 我会检查你的响应回调中的状态码,如果它不等于 200,则引发错误。
  • 哦,对不起@Keith,我想我并不清楚。成功取决于响应。 200 码不一定足够。
  • 编辑了我的评论。在我完成输入之前,我会点击“添加”。
  • 我并不是说 200 就足够了,您仍然需要检查状态响应,您可能会收到 503 Service Unavailable 或其他内容。所以你仍然会得到响应,但你不会收到任何dataend 事件,所以会挂起,因为你永远不会调用你的回调。
  • 老实说,你并没有那么远,我将发布一个带有额外检查的小 sn-p。哦,刚刚注意到你找到了一个链接,是的.. 实施额外检查,你应该很高兴..

标签: javascript node.js http request


【解决方案1】:

你是不是错过了.end()

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

类似here 的解释。

【讨论】:

    【解决方案2】:

    在您的响应回调中,您没有检查状态..

    .on('error', handle_error); 用于连接到服务器时发生的错误,状态码错误是服务器在连接成功后响应的错误。

    通常,200 状态响应是您对成功请求的期望..

    所以应该对你的 http.get 做一个小模块来处理这个问题..

    例如。

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

    【讨论】:

    • 不幸的是,这似乎不是解决方案。我添加了这个,它仍然会在一夜之间定期挂起。我添加了一些额外的登录来尝试确定它到底在哪里。当我得到它们时,我会更新我的帖子以提供更多详细信息。
    • 哦,另一个想法。也许错误是没有得到连接,但是在连接过程中..尝试把response.on('error', handle_error);
    • 现在试试这个!只需要等待它出现 a) 错误,或 b) 挂起。这基本上是随机的,似乎在一夜之间发生。
    • 不走运。事实上,我在回调中添加了一个控制台日志,显然它甚至从未被调用过。
    • 我的想法已经不多了 :(,但一个想法可能是做 npm 请求所做的事情并创建自己的超时。另外我假设您正在运行的节点版本大于等于 v6.8.0 ,因为那是添加超时选项的时候。
    猜你喜欢
    • 2020-01-31
    • 2022-06-30
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多