-
Notifications
You must be signed in to change notification settings - Fork 8
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
Add a Receiver.close()
method
#348
base: v1.x.x
Are you sure you want to change the base?
Conversation
Still need to add tests. |
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.
LGTM but the CI is failing, and this reminds me that it would be good to add tests at least for the receivers that actually do something when close()
is called.
And oh, yes! As usual names, names, names 😆
TL;DR: All good the name actually, just some other comments about future directions.
I was going to suggest to rename close()
to stop()
, for once to match the ReceiverStoppedError
but also to match the upcoming Service
interface.
But I see close actually wait for the current buffer to be consumed, my idea for stop()
would be that stuff gets just dropped.
Maybe to make it play better with Service
we can keep close()
as you implemented it, as a "graceful" shutdown, and when we introduce Service
we can use cancel()
to drop the current buffers. Then maybe stop()
can take an option to decide if close()
or cancel()
is called (stop is usually implemented as self.cancel(); await self
).
Yes, I'm already working on tests in this same branch, just made an early PR because the code is ready for review.
I think |
Mmm, receiver don't need to have task, but many do (like But maybe there are other solutions to this. We can discuss this when the time comes. |
Please let me know when this is ready for a final review :) |
That doesn't sound like an issue, because people still call And calling |
But If we make |
Classes that implement the `Sender` or `Receiver` interfaces currently need to override the `send` or the `ready` and `consume` methods respectively. As we add more methods, to these interfaces, it becomes hard to track which methods are there for internal use and which ones are there to implement the interface. Using the `override` decorators helps with that. Signed-off-by: Sahas Subramanian <[email protected]>
Also implement the method in all classes implementing the `Receiver` interface. Signed-off-by: Sahas Subramanian <[email protected]>
This makes it consistent with the channel close method, which is async. It also makes it easy to fully stop any pending tasks, as is the case with `merge`. Signed-off-by: Sahas Subramanian <[email protected]>
Signed-off-by: Sahas Subramanian <[email protected]>
Signed-off-by: Sahas Subramanian <[email protected]>
This is ready, the only big change is that |
Last push to have a (
|
BTW, the method can't be abstract, otherwise this is a breaking change. We need to provide a default empty implementation I guess. We can create an issue to make the method abstract for 2.0. |
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.
I didn't review everything, because I think the review will change a lot depending on what we do with close
vs stop()
(stop()
being close()
/cancel()
+ __await__
).
cancel()
and __await__
are actually the 2 primitives used by (Background
)Service
too, based on Task
, and the more I look at it, the more I think receivers should follow this interface too.
@override | ||
async def close(self) -> None: | ||
"""Close this receiver.""" | ||
self._stop_event.set() |
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.
We should probably do a await self._awatch.aclose()
here to make sure all the threads from the awatch are stopped too. Maybe even mark the receiver somehow as stopped so ready()
doesn ´t try to use self._awatch
again? Not sure what would happen otherwise, what kind of exception would be raised.
|
||
After closing, the receiver will not be able to receive any more messages. | ||
""" | ||
self._closed = True |
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.
I think here we should also break the ready()
if it is waiting for the condition variable. I guess this would mean adding a an event and then async.wait()
on the first one to complete in ready()
?
I guess this is actually the difference between closing and stopping. Close is basically analogous to Task.cancel()
, it is like it schedules the stopping. And it is actually probably a good idea to have it separated, but we are still missing the await
then, making stop()
async but then not actually awaiting for anything seems weird to me.
This method would allow individual receivers to be closed, without affecting the underlying channel, if there is one.