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

ServerCertificateSelector callback needs to be async, otherwise any async work in callback may cause deadlock with threadpool (eg. logging failure to disk). #20981

Closed
rickyburrell opened this issue Apr 18, 2020 · 5 comments
Assignees
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions feature-kestrel
Milestone

Comments

@rickyburrell
Copy link

We have a kestrel based production load balancer edge hosted on large site.

When malicious clients open many https connections based on invalid host names, no cert is available and we async log this failure to W3C log file.

As the callback method is not async, we end up blocking most of the thread pool threads waiting for async logging to be scheduled and starvation occurs.

Surely it is easy enough to make this callback async?

tasks
threads PNG

@analogrelay
Copy link
Contributor

Yep, this is something we’re actively looking at. The callback itself actually lives in the ru time though. @karelz @wfurt is there a bug tracking that work on the runtime?

For your use case though (it sounds like you’re logging?), I’d suggest something like a fire-and-forget async pattern or using a queue and background worker rather than blocking the callback inline. Even with an async callback, you wouldn’t want to keep the connection open while you’re logging. If the callback is async and you put your logging code inline in there, Kestrel won’t be able to release the connection until the callback completes fully.

A fire-and-forget pattern means using something like Task.Run, or calling an async method without awaiting the task. The critical part is not blocking the current thread on the result. If you do that, it’s important to make sure the method you fire-and-forget has exception handling and logging built in because if it throws an exception, it won’t be logged by Kestrel since it happened outside the request/connection scope. This could still cause some thread-pool pressure in a scenario with a lot of malicious requests though.

A background queue worker approach would mean synchronously adding a message to a queue in the callback and having a background task using IHostedService come along to periodically write out all the queued log messages. The trade-off here is that you have to buffer all these messages in memory until the background task can come along. It might be best to have a limit to the number of queued messages and just drop messages if the buffer is full (since you probably don’t need every single log message if you’re being stormed by malicious clients). You could also just track a count of bad requests (perhaps by host name), which would take a lot less memory usage.

@wfurt
Copy link
Member

wfurt commented Apr 18, 2020

I did not find any issue just describing the async version. As @anurse mentioned it is on 5.0 TODO list and will be probably done as part of dotnet/runtime#31097. If it helps we can create separate issue just for the Async version.

@analogrelay
Copy link
Contributor

I’m not worried about how it’s tracked in the runtime end @wfurt . I think we should keep this issue though since there’s a small amount of work Kestrel will need to do to expose the new callback.

@rickyburrell
Copy link
Author

Hi Andrew, thanks for the feedback. We have already implemented a workaround as suggested, but the ideal solution would require that the error is logged: at the same time; and as a part of the connection termination process; and that back-pressure is exerted. We would appreciate any work done here - looking forward to this feature in a future version.

@analogrelay analogrelay added blocked The work on this issue is blocked due to some dependency cost: XS labels Apr 20, 2020
@analogrelay
Copy link
Contributor

Triage: Blocked by the runtime change to add this to SslStream. Once we have that, we'll need to do a small amount of work to expose it.

@analogrelay analogrelay added this to the 5.0.0 milestone Apr 22, 2020
@BrennanConroy BrennanConroy modified the milestones: 5.0.0, 5.0.0-rc1 Jul 27, 2020
@BrennanConroy BrennanConroy removed the blocked The work on this issue is blocked due to some dependency label Jul 27, 2020
@BrennanConroy BrennanConroy added api-needs-work API needs work before it is approved, it is NOT ready for implementation and removed cost: XS labels Aug 19, 2020
@halter73 halter73 closed this as completed Sep 1, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Oct 1, 2020
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions feature-kestrel
Projects
None yet
Development

No branches or pull requests

8 participants