Skip to content

Support adding services while ServiceGroup is running #199

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

Merged

Conversation

sliemeobn
Copy link
Contributor

somewhat straight-forward implementation draft of
#185

choices were made, what do we think?

Copy link
Contributor

@FranzBusch FranzBusch left a comment

Choose a reason for hiding this comment

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

This is a great start. Thanks for working on this. I left some feedback inline.

@sliemeobn
Copy link
Contributor Author

ok, merging the addService and the taskGroups signals into the main run loop is a lot tougher than expected...
I think I'd need something like a non-sendable, non-escaping merged iterator that can handle this.

but the async algorithms package only has a sendable-required merge function.

how off am I? any better ideas?

@FranzBusch
Copy link
Contributor

ok, merging the addService and the taskGroups signals into the main run loop is a lot tougher than expected... I think I'd need something like a non-sendable, non-escaping merged iterator that can handle this.

but the async algorithms package only has a sendable-required merge function.

how off am I? any better ideas?

Yeah I expected you run into this. So the problem is that TaskGroup is not Sendable because it can't be iterated concurrently. What we could do is send the iterator of the async channel into a child task, then consume the next service once, return it from that child task similar to how all other child tasks are returning one case of an enum. Then we add the service and spawn another task consuming off the next service that needs to be added.

This way we only have to transfer the iterator of the channel in and out of child tasks which requires some unchecked sendable but is totally safe. Does that make sense?

@sliemeobn
Copy link
Contributor Author

^^ I was just coding this exact thing, but I wasn't sure if it is too crazy ; )
I'll see how it goes...

@sliemeobn
Copy link
Contributor Author

@FranzBusch I managed to clean up the channel reading, I think that part is good enough now.

The remaining question is what to do with added services during shutdown or cancel?

If we want a reliable back-propagation of "has it run or not?" we'll need to pass along a continuation I think and we'd need to make sure to fully drain and actively "reject" all added service until we set the status to .finished.

A lot of brittle and racy signaling... if we simply ignored (like now) life would be a lot easier ; )

@sliemeobn
Copy link
Contributor Author

thanks @FranzBusch for the quick reviews!

I addressed the feedback from above, but I am still a bit scared of the "best effort" nature of it.

So, as a suggestion, I renamed the function to addServiceUnlessShutdown to better communicate its best-effort nature (similar to TaskGroup.addTaskUnlessCanceled).

This would also allow us to one day add a addService that maybe always runs and immediately shuts down, and maybe throws if the group was canceled or has shutdown. (or similar, should the need arise)

wdyt?

Copy link
Contributor

@FranzBusch FranzBusch left a comment

Choose a reason for hiding this comment

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

This looks great. I'm happy with the new name and the implementation looks good to me. Just one last nit around the comment

@FranzBusch FranzBusch added the 🆕 semver/minor Adds new public API. label Mar 6, 2025
@FranzBusch
Copy link
Contributor

@sliemeobn can you fix the license header check please

@sliemeobn
Copy link
Contributor Author

sliemeobn commented Mar 6, 2025

can you fix the license header check please

@FranzBusch oops, done

(is there an easy way to run the soundness checks locally?)

@FranzBusch FranzBusch enabled auto-merge (squash) March 8, 2025 11:15
@FranzBusch
Copy link
Contributor

can you fix the license header check please

@FranzBusch oops, done

(is there an easy way to run the soundness checks locally?)

Yeah you can use act to run all of it locally. There is some documentation here: https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally

@FranzBusch FranzBusch merged commit 7ee57f9 into swift-server:main Mar 8, 2025
22 checks passed
@sliemeobn sliemeobn deleted the feature/add-services-dynamically branch March 8, 2025 13:22
///
/// If the group is currently running, the added service will be started immediately.
/// If the group is gracefully shutting down, cancelling, or already finished, the added service will not be started.
/// - Parameters:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Apologies for the late review - it'd be great to call out that this can also be used for adding services before the group was started. Right now the comment leaves that ambiguous of what happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🆕 semver/minor Adds new public API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants