Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure ping in HTTP2 #40257

Merged
merged 35 commits into from
Aug 13, 2020
Merged

Configure ping in HTTP2 #40257

merged 35 commits into from
Aug 13, 2020

Conversation

aik-jahoda
Copy link
Contributor

@aik-jahoda aik-jahoda commented Aug 3, 2020

Allows configure HTTP2 ping on SocketsHttpHandler:

namespace System.Net.Http
{
    public class SocketsHttpHandler
    {
        public TimeSpan KeepAlivePingDelay { get; set; }
        public TimeSpan KeepAlivePingTimeout { get; set; }
        public HttpKeepAlivePingPolicy KeepAlivePingPolicy { get; set; }
    }
    public enum HttpKeepAlivePingPolicy
    {
        WithActiveRequests,
        Always
    }
}

The KeepAlivePingDelay defines how often the ping is sent. Any incoming frame can postpone the ping request. It means during vivacious communication the ping will not be sent at all as the communication itself manifest the connection is live. The time resolution is 1s.

KeepAlivePingTimeout defines the ping ack timeout. The time resolution is 1s.

KeepAlivePingPolicy defines in what circumstances the ping is sent:

  1. WithActiveRequests - only if the connection has an active stream
  2. Always - send the ping always - even if the connection is returned to the connection pool and no streams are active.

When the ping detects the connection is active, it closes the connection.

What to expect

  • The connection is closed as soon as possible, not during Send attempt
  • A proxy will not close connection with active frame flow

What to not expect

  • Connection latency - the API don't measure connection latency

fixes #31198

Jan Jahoda added 2 commits July 28, 2020 10:41
@Dotnet-GitSync-Bot
Copy link
Collaborator

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@aik-jahoda aik-jahoda changed the title Jajahoda/httpping Configure ping in HTTP2 Aug 3, 2020
Copy link
Member

@ManickaP ManickaP left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two major questions:

  • Is the timer with HeartBeat right approach?
  • Is it worth the extra class Http2KeepAlive?

@scalablecory you're opinions?

Copy link
Contributor

@scalablecory scalablecory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass review done; will provide a 2nd pass once comments are resolved.

@ManickaP
Copy link
Member

ManickaP commented Aug 4, 2020

Just thinking, but instead of the HeartBeat timer, could we just make a method with a loop with await Task.Delay(PingDelay)? Similar to ProcessIncomingFrames, i.e. started but not awaited:
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L158

However, I don't know if this would be worse or better on the resources than the shared timer across all connections.

{
thisRef.HeartBeat();
}
}, new WeakReference<HttpConnectionPoolManager>(this), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All implementations I have seen of pinging says that unreasonably low values for ping delay and timeout are not allowed.

1 second for the heartbeat is fine - this is what we do in Kestrel - but I think the KeepAlivePingDelay and KeepAlivePingTimeout should disallow values smaller than a second. That way developers won't expect to be able to configure KeepAlivePingDelay = TimeSpan.FromMillisecond(1) and expect a ping to be sent every millisecond.

@JamesNK
Copy link
Member

JamesNK commented Aug 5, 2020

Just thinking, but instead of the HeartBeat timer, could we just make a method with a loop with await Task.Delay(PingDelay)? Similar to ProcessIncomingFrames, i.e. started but not awaited:
master/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L158

However, I don't know if this would be worse or better on the resources than the shared timer across all connections.

One problem is time would slowly drift. Each iteration would be PingDelay + time to execute heartbeat logic. You'd need to calculate that time and subtract it from PingDelay when doing the next delay. Even with that time would probably slowly drift.

I haven't looked at the Timer source but it will no doubt have optimizations that make it a better choice than Task.Delay calls in a loop.

@scalablecory
Copy link
Contributor

Just thinking, but instead of the HeartBeat timer, could we just make a method with a loop with await Task.Delay(PingDelay)? Similar to ProcessIncomingFrames, i.e. started but not awaited:
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L158

However, I don't know if this would be worse or better on the resources than the shared timer across all connections.

I haven't looked at the Timer source but it will no doubt have optimizations that make it a better choice than Task.Delay calls in a loop.

Using Timer here is a lot more efficient. Timer has no allocations once it is going. Task.Delay allocates a new timer for every call.

@ManickaP
Copy link
Member

ManickaP commented Aug 5, 2020

Just thinking, but instead of the HeartBeat timer, could we just make a method with a loop with await Task.Delay(PingDelay)? Similar to ProcessIncomingFrames, i.e. started but not awaited:
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L158

However, I don't know if this would be worse or better on the resources than the shared timer across all connections.

I haven't looked at the Timer source but it will no doubt have optimizations that make it a better choice than Task.Delay calls in a loop.

Using Timer here is a lot more efficient. Timer has no allocations once it is going. Task.Delay allocates a new timer for every call.

Cool, it was just a suggestion. And I learned something new. Keep the heartbeat.

@aik-jahoda aik-jahoda requested a review from JamesNK August 5, 2020 14:59
@ManickaP
Copy link
Member

/azp run runtime-libraries outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@ManickaP ManickaP self-assigned this Aug 12, 2020
On slower platforms, PINGs were coming sooner than requests themselves causing errors while reading the request and receiving PING frame instead of HEADERS frame.
@ManickaP
Copy link
Member

/azp run runtime-libraries outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@ManickaP
Copy link
Member

/azp run runtime-libraries outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@ManickaP
Copy link
Member

/azp run runtime-libraries outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@ManickaP
Copy link
Member

/azp run runtime-libraries outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@ManickaP ManickaP merged commit 4a436e3 into dotnet:master Aug 13, 2020
@MihaZupan
Copy link
Member

@ManickaP FYI The Http2_PingKeepAlive outerloop test seems to be failing quite a bit

@karelz
Copy link
Member

karelz commented Aug 13, 2020

Is there a bug tracking the failure?

@ManickaP
Copy link
Member

ManickaP commented Aug 13, 2020

It's bug in test, no need for tracking issue, I'm working on it right know.
PR's up: #40788

@karelz karelz added this to the 5.0.0 milestone Aug 18, 2020
@aik-jahoda
Copy link
Contributor Author

@ManickaP, thanks for finish this PR!

@aik-jahoda aik-jahoda deleted the jajahoda/httpping branch August 24, 2020 11:23
@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

configurable HTTP/2 PING timeouts in HttpClient
8 participants