镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

http2: [8.x] server stream emits error after close #24559

Description

@Flarna
  • Version: 8.13.0
  • Platform: Tested on Windows I expect it's platform independent
  • Subsystem: http2

With 8.13.0 http2 server stream emits error after close whereas 10.13.0 and 11.2.0 emit error before close.

I was expecting that 8.13.0 acts like 10.13.0 as http2 is out of experimental now and quite a lot was backported to reach parity.
The sequence is not documented to my understanding but I have the feeling that error should come first.

In my use case (APM) the consequence is that I can't attach the error event to the server transaction as this one is already closed.

Reproducer:

const { createServer, connect } = require('http2');

createServer()
  .on('stream', (stream) => {
    console.log('ServerStream created');
    stream
      .on('close', () => console.log('ServerStream close'))
      .on('error', (err) => console.log('ServerStream error'))
      .respondWithFile('dont exist');;
  })
  .listen(8000);

connect('http://localhost:8000').request()
  .on('response', () => console.log('response'))
  .on('error', () => console.log('ClientRequest error'));

prints:

for 8.13.0:
ServerStream created
ServerStream close
ServerStream error
ClientRequest error

for 10.13.0/11.2.0:
ServerStream created
ServerStream error
ServerStream close
ClientRequest error

Refs: #22850

Activity

  1. ofrobots commented on Nov 21, 2018

    @ofrobots
    Contributor

    /cc @nodejs/http2

  2. self-assigned this
    on Nov 22, 2018
  3. MylesBorins commented on Nov 27, 2018

    @MylesBorins
    Contributor

    I've opened a PR with a test for this... gonna start digging

    #24685

  4. MylesBorins commented on Nov 27, 2018

    @MylesBorins
    Contributor

    So it would appear that the change that introduced this behavior difference landed in 10.x... as the order is consistent all the way through 9.x.

    I believe it is this Semver-Major change to net

    net: emit 'close' after 'end'

    As such I think that this behavior difference is expected, and unfortunately not something that can be fixed. I'll let someone else chime in to confirm. Perhaps it makes sense to document this?

  5. MylesBorins commented on Nov 27, 2018

    @MylesBorins
    Contributor
  6. mcollina commented on Nov 27, 2018

    @mcollina
    SponsorMember

    Emitting error after close is a bug. In a lot of cases, an hard-to-solve one. I’m inclined to consider this just a bug.

    (bugs could be semver-major)

  7. MylesBorins commented on Nov 28, 2018

    @MylesBorins
    Contributor

    @mcollina are you suggesting we change the behavior in net in 8.x LTS?

  8. mcollina commented on Nov 28, 2018

    @mcollina
    SponsorMember

    No, we should fix http2 everywhere.

  9. lpinca commented on Nov 28, 2018

    @lpinca
    Member

    I don't think backporting #19241 is an option. It's definitely semver-major.

  10. MylesBorins commented on Nov 28, 2018

    @MylesBorins
    Contributor

    to add to what @lpinca said... the issue here is not http2 it is net, which I don't think we can change

  11. mcollina commented on Nov 28, 2018

    @mcollina
    SponsorMember

    @MylesBorins I'm proposing we fix http2 to handle this new event ordering correctly. Worst case, we swallow the error. IMHO after 'close' no error should be emitted. This change might be semver-major, but that's a different decision.

    I agree we should not revert the change in net.

  12. lpinca commented on Nov 28, 2018

    @lpinca
    Member

    @mcollina I like you proposal. I'm not sure what it means in practice though, wouldn't it make future backports harder or is the plan to apply the changes on master first?

  13. mcollina commented on Nov 28, 2018

    @mcollina
    SponsorMember

    I would apply the changes on master first, and backport as usual.

  14. Flarna commented on Nov 28, 2018

    @Flarna
    MemberAuthor

    I haven't digged into this yet but I wonder why a net change should impact the ordering of events on a single http2 stream. The TCP connection (net) is not closed in the use case above.

  15. lpinca commented on Nov 28, 2018

    @lpinca
    Member

    If there is no issue on master how would you fix something that isn't broken? I mean how do you justify the change?

  16. mcollina commented on Nov 28, 2018

    @mcollina
    SponsorMember

    Oh I misunderstood the issue. Then we should probably work on a fix on Node 8 to address the situation. This is probably going to be very hard.

    IMHO it's better than we just swallow the error on Node 8. Unfortunately this is going to make the backports harder.

  17. Flarna commented on Nov 29, 2018

    @Flarna
    MemberAuthor

    I did some debugging and I think #19836 is the change which fixed this in Node >= 10.

  18. MylesBorins commented on Nov 29, 2018

    @MylesBorins
    Contributor

    #19836 is built on top of #18438 which landed on v10.0.0

    As the behavior for the test we wrote passes on 10.x I'm not 100% sure that #19836 is the PR that fixed it... but we can dig in a bit and see if we can get something working

  19. Flarna commented on Nov 29, 2018

    @Flarna
    MemberAuthor

    Yes, it seems it's a combination of these. Also #19451 seems to be involved.
    I got following call chain:

    respondWithFile => fs.open() ==>
    afterOpen() => this.destroy(err) => this._destroy()

    NodeJS 8:
    ServerHttp2Stream._destroy() calls process.nextTick(emit, this, 'close', code) => close comes first
    Callback passed to _destroy() does a process.nextTick(emitErrorNT, this, err)

    NodeJS 10:
    Callback passed to _destroy() does a process.nextTick(emitErrorAndCloseNT, this, err) ==> emits first error then close
    ==> the process.nextTick(emit, this, 'close', code); in ServerHttp2Stream._destroy() has been removed in #19451

  20. MylesBorins commented on Nov 29, 2018

    @MylesBorins
    Contributor

    #19451 has already landed on 8.x in e4c10e1 fwiw

  21. Flarna commented on Nov 29, 2018

    @Flarna
    MemberAuthor

    But not the complete change - the line process.nextTick(emit, this, 'close', code) in _destroy() is still there. Most likely because #19836 and/or #18438 have not been backported.

  22. Flarna commented on Dec 2, 2018

    @Flarna
    MemberAuthor

    I have a fix in http2 to correct the sequence but I found that v8.x has a test which verifies that error comes after close.... This test was adapted in #17406 to verify close is after error.

    Edit: PR: #24789

    Should I submit a PR to correct the sequence or is this anyway something which can't be done in a patch/minor release?

  23. Flarna commented on Dec 11, 2018

    @Flarna
    MemberAuthor

    fixed via #24789

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions