nodejs / nodejs/node

error handler of same domain can be called several times when it throws

未关闭
#25,505 3 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

domain help wanted
主要语言
JavaScript
星标
122k
派生
37.4k
平均合并
4 天 3 小时
30 天内合并 PR
272

描述

  • Version: Current tip of master (66f45e7e5b), but probably applies to all versions.
  • Platform: All platforms.
  • Subsystem: domain.

The following code:

'use strict';

const common = require('../common');
const domain = require('domain');
const http = require('http');

const server = http.createServer((req, res) => {
  res.end();
});

let numDomainErrorListenerCalls = 0;

function performHttpRequestWithDomain(cb) {
  const d = domain.create();
  d.run(() => {
    const req = http.get({
      host: '127.0.0.1', port: server.address().port
    }, (res) => {
      res.on('data', () => {});
      res.on('end', () => {
        throw new Error('bang');
      });
    });

    req.end();
  });

  d.on('error', (domainErr) => {
    console.log(++numDomainErrorListenerCalls);
    throw new Error('boom');
  });
}

server.listen(0, '127.0.0.1', () => {
  performHttpRequestWithDomain(common.mustCall(() => {
    server.close();
  }));
});

gives the following output:

$ ./node test/parallel/test-http-req-domain-stack.js 
1
2
/Users/jgilli/dev/node/test/parallel/test-http-req-domain-stack.js:30
    throw new Error('boom');
    ^

Error: boom
    at Domain.d.on (/Users/jgilli/dev/node/test/parallel/test-http-req-domain-stack.js:30:11)
    at Domain.emit (events.js:188:13)
    at Domain.EventEmitter.emit (domain.js:430:20)
    at Domain._errorHandler (domain.js:216:23)
    at Domain._errorHandler (domain.js:244:33)
    at Object.setUncaughtExceptionCaptureCallback (domain.js:132:29)
    at process._fatalException (internal/process/execution.js:102:29)

The uncaught exception is expected. What is not expected as far as I understand is for the same domain's error handler to run more than once.

I believe the original intention of the domain's implementation is to pop the domains stack when a domain's error handler throw, so that the domain that handles that new error is the "parent" domain.

However, in the example above the same domain is pushed on the stack more than once. For instance, when an event is emitted from a nextTick callback, the same domain will be entered from the nextTick callbacks scheduler and then once again from the event emitter.

Pushing the same domain on the stack more than once makes sense so that the components that push a domain can pop it from the stack. However, I think we could probably replace the call to pop the stack once in the domain error handling code to remove all consecutive instances of that domain instead.

@nodejs/domains Thoughts?

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 test/parallel/test-http-req-domain-stack.js 开始,重现 error listener 被重复调用的情况。结合 internal/process/next_tick.js 阅读 lib/domain.js,尤其关注其中引用的 stack 处理路径。当回归问题已有覆盖,并且同一 domain 的 error handler 在抛出异常时不再被重复调用,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
javascript, nodejs
领域
backend, testing
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
冷清
描述清晰度
基本清楚
新手友好度
48/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。