Skip to content

Switching to undici breaks long-lived connections to Apple, and never returns from the send call #97

@kohenkatz

Description

@kohenkatz

In 11.x and previous versions, the fetch-http2 library would issue HTTP/2 PING frames if the keepAlive option was set (by calling the node:http2 Http2Session.ping method).

However, undici does not implement HTTP/2 PING frames at all. The keepalive option on undici's Pool just sends TCP keepalive, not HTTP/2 keepalive.

Apple's documentation for APNs best practices explicitly states that PING frames can be sent to keep the connection open if it has not been used for an hour. Just sending TCP keepalive is apparently not enough.

In the last two weeks, Apple has started not responding to connections that have been open for a long time without sending PINGs.

We see this clearly when using a server that opens long-lived connections to APNs - messages are sent fine for several hours, followed by a several hour break. After the break, Apple stops responding to our messages.

When using @parse/node-apn, this returns with an error that there has been a timeout. However, this package doesn't implement a timeout, so the call to await client.send() blocks forever.

Blocking forever, waiting for a response that will never come, seems like a major problem to me.

I don't think there's a way to hook into undici at a low enough level to send PING frames, but I'm trying to figure out which of these makes the most sense:

  1. Move back off of unidici to your fetch-http2 library again - this would lose the built-in connection pooling
  2. Try to get undici to implement HTTP/2 PING - not sure what is the level of effort and the time frame to do that
  3. Temporary Workaround - use undici Pool's clientTtl option to prevent clients from lasting longer than an hour. This goes against Apple's recommendations, but would probably prevent the issue from happening until a more permanent fix can be done. (Also, this is a new undici feature that was added last week and has not been released yet.)

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions