-
Notifications
You must be signed in to change notification settings - Fork 633
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
Better align shutdown semantics of testing event loops #2800
base: main
Are you sure you want to change the base?
Conversation
@@ -95,6 +95,10 @@ public final class NIOAsyncTestingEventLoop: EventLoop, @unchecked Sendable { | |||
/// The queue on which we run all our operations. | |||
private let queue = DispatchQueue(label: "io.swiftnio.AsyncEmbeddedEventLoop") | |||
|
|||
private enum State: Int, AtomicValue { case open, closing, closed } | |||
private let _state = ManagedAtomic(State.open) | |||
private var state: State { self._state.load(ordering: .relaxed) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The atomic ordering here seems likely to be logically wrong. We should probably force ourselves to express it at all points.
@@ -150,6 +154,15 @@ public final class NIOAsyncTestingEventLoop: EventLoop, @unchecked Sendable { | |||
let promise: EventLoopPromise<T> = self.makePromise() | |||
let taskID = self.scheduledTaskCounter.loadThenWrappingIncrement(ordering: .relaxed) | |||
|
|||
switch self.state { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The load here should be acquiring
.
@@ -324,9 +334,11 @@ public final class NIOAsyncTestingEventLoop: EventLoop, @unchecked Sendable { | |||
|
|||
/// The concurrency-aware equivalent of `shutdownGracefully(queue:_:)`. | |||
public func shutdownGracefully() async { | |||
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in | |||
await withCheckedContinuation { continuation in | |||
self._state.store(.closing, ordering: .relaxed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These stores should be releasing
.
Motivation:
The two testing event loops—
EmbeddedEventLoop
andNIOAsyncTestingEventLoop
—have different semantics for outstanding work during shutdown, which are both different from the productionSelectableEventLoop
, specifically with newly scheduled tasks that result from running existing scheduled work at the time of shutdown.There are three axes to consider:
SelectableEventLoop
EmbeddedEventLoop
NIOAsyncTestingEventLoop
Note that
NIOAsyncTestingEventLoop
may never terminate because of this.Modifications:
This PR aligns
EmbeddedEventLoop
andNIOTestingEventLoop
and makes them more similar toSelectableEventLoop
and less surprising semantics.Result:
SelectableEventLoop
EmbeddedEventLoop
NIOAsyncTestingEventLoop
Future work:
Given both the
EmbeddedEventLoop
andNIOAsyncTestingEventLoop
are used in tests of NIO applications that run withSelectableEventLoop
in production, it might be worth extending both to also support quiescing to give a more representative shutdown behaviour in tests.