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

Support adding/removing socket listeners on already running servers #159

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

jooooel
Copy link

@jooooel jooooel commented Jan 7, 2023

I'm working on adding support for starting and stopping individual services in Project Tye, without restarting Tye entirely. One thing I'm missing is support for adding and removing socket listeners to an already running BedrockFramework server (needed by the ProxyService in Tye).

I've taken a shot at implementing that here, with the hope that it could get released into a new nuget version and be used in my fork of Tye.

I took the liberty to add some tests for this new behaviour. Maybe it's arguable if they are unit or integration tests (because of the use of sockets etc), but they seem to run fine.

Hope you're open to this change, and please let me know if you'd like me to change it it any way 😊

@davidfowl
Copy link
Owner

This needs to be thread safe.

@jooooel jooooel force-pushed the jooooel/add_socket_support branch from 32530ac to 9543a57 Compare January 28, 2023 12:55
- Make it possible to add and remove socket listeners to already running
servers. Relies on the existing methods, just adds and removes
"RunningListeners" as needed. Backed by Dictionary instead of List to
simplify lookups
- Handle concurrency by using a SemaphorSlim, similar to how it's done
in Kestrel
- Added equivalent methods to ServerHostedService, since the Server
itself isn't accessible.
- Added some test coverage for the new behavior.
@jooooel jooooel force-pushed the jooooel/add_socket_support branch from 9543a57 to 2b6e433 Compare January 28, 2023 12:59
@jooooel
Copy link
Author

jooooel commented Jan 28, 2023

@davidfowl Oh, you're right! Didn't think about that :) I don't often come across areas where I have to think about thread safety in my daily work, but I've given it a go here. Let me know if there are any gotchas or something special to look out for...

And I'm not really sure how to solve this the best way. I started out with a ConcurrentDictionary for the RunningListeners, but I soon realised that wasn’t enough. So I went for a simple locking instead. This way, the server will have to wait until any Add/Remove operation has finished, and vice versa. I took a look at how Kestrel handles similar cases, and was inspired by that.

I think I need a bit of help reasoning about the heartbeat timer, if there are possible concurrency issues there as well. I guess the risk is that a listener currently/already being stopped receives a call to TickHeartBeat(). However, this isn’t being handled while the server is shutting down in the current implementation anyway, so maybe it’s not something to bother about?

@jooooel
Copy link
Author

jooooel commented Jan 28, 2023

But basically all I did was to await a SemaphoreSlim in places where the RunningListeners are handled. And store them in a Dictionary to simplify lookups.

@jooooel
Copy link
Author

jooooel commented Jan 28, 2023

And by the way. Do with this what you will 😊 I’m not expecting you to spend any of your free time on me and my tinkering

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants