为啥 HTTPs 节点库中的回调被调用两次?如何预防?

Posted

技术标签:

【中文标题】为啥 HTTPs 节点库中的回调被调用两次?如何预防?【英文标题】:Why is callback in HTTPs node library being called twice? How to prevent it?为什么 HTTPs 节点库中的回调被调用两次?如何预防? 【发布时间】:2019-11-28 20:27:23 【问题描述】:

我有一个节点代码,它本质上是工作队列处理器。 我在大约 10 个进程的集群中运行它。

worker 处理的每个作业都使用下面粘贴的函数发出传出 HTTPs 请求:

注意 done();调用,它应该通知队列处理器作业处理已完成 - 成功或失败。 对于 https 请求,我使用包含“follow-redirects”模块的标准节点库。

我遇到的问题是,每隔 X 分钟,我的一名工作人员就会崩溃,并显示以下错误消息。 据我了解,这意味着在“error_callback”中多次调用了“done()”。

如何防止这种行为? 在异常处理程序中嵌入 done() 调用会在这里工作吗?有没有更好的解决方案?

[2019-07-19 22:19:23] error: uncaughtException: the deferred callback has already been called
Error: the deferred callback has already been called
    at callback (/root/node_modules/promise-callbacks/src/callbackBuilder.js:20:13)
    at Object.error_callback (/root/lib/ways.js:115:9) (function from this file is attached below)
    at RedirectableRequest.emit (events.js:189:13)
    at ClientRequest.eventHandlers.(anonymous function) (/root/node_modules/follow-redirects/index.js:17:24)
    at ClientRequest.emit (events.js:189:13)
    at TLSSocket.socketErrorListener (_http_client.js:392:9)
    at TLSSocket.emit (events.js:189:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process._tickCallback (internal/process/next_tick.js:63:19)
        done(null, host: this.host, code: statusCode); //notify queue processor of success with inclusion of results
        done(e); //notify queue processor of failure with inclusion of error message

var http = require('follow-redirects').https;

exports.processLowLevel = function (url, index, done, SOCKET_TIMEOUT, HTTP_TIMEOUT, WRITE_RESULTS) 
    let url_parsed = require('url').parse(url);

    let response_callback = function (resp) 
        console.log(`[$index] Response: $this.host - $resp.statusCode`);

        done(null, host: this.host, code: resp.statusCode); //notify queue processor of success
        return "";

    ;

    let error_callback = function (e) 

        console.error(`[$index] Error callback: $this.host $e.message`);

        e.host = this.host;

        done(e); //notify queue processor of FAILURE

        return "";

    ;

    const options = 
        hostname: url_parsed.host,
        path: url_parsed.path,
        method: 'GET',
        timeout: HTTP_TIMEOUT * 1000,
    ;

    options.maxRedirects = 4;


    let callback_data = 'host': url_parsed.host, 'index': index;

    const req = http.request(options, response_callback.bind(callback_data));
    req.on('error', error_callback.bind(callback_data));
    req.end();
;

【问题讨论】:

【参考方案1】:

不太确定这是否有帮助.. 但在 response_callback 而不是:

done(null, host: this.host, code: resp.statusCode); //notify queue processor of success
        return "";

试试

return done(null, host: this.host, code: resp.statusCode);

和error_callback一样,试试:

return done(e);

【讨论】:

以上是关于为啥 HTTPs 节点库中的回调被调用两次?如何预防?的主要内容,如果未能解决你的问题,请参考以下文章

为啥构造函数被调用两次

.animate() 的回调被调用两次 jquery

为啥即使回调参数与 XML 中的参数不匹配,GObject 方法仍会被调用?

为啥 UITableView 自定义单元格的第一个单元格总是在 Xcode 中的动作事件上被调用两次

在非回调函数上调用 promisify():“有趣”的结果是节点。为啥?

为啥 ngOnInit 被调用两次?