-
Notifications
You must be signed in to change notification settings - Fork 269
Http CloseHandle for closing while waiting #331
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
Conversation
…ain server thread
bkchr
left a comment
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.
Looks good so far. Some minor nitpicks :)
http/src/lib.rs
Outdated
|
|
||
| /// A handle that allows closing of a server even if it owned by a thread blocked in `wait`. | ||
| pub struct CloseHandle { | ||
| close: Arc<Mutex<Option<Vec<oneshot::Sender<()>>>>>, |
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.
More whitespaces.
| } | ||
|
|
||
| /// A handle that allows closing of a server even if it owned by a thread blocked in `wait`. | ||
| pub struct CloseHandle { |
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 we should implement/derive Clone for the CloseHandle.
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.
futures::Sender, doesn't implement Clone(), so how should we approach this?
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.
Do you mean the executor_close can not be cloned?
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.
@carllin it's wrapped in Arc<Mutex anyway, so it doesn't really matter. If derive doesn't work then you need to implement Clone manually (and just clone the Arc)
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.
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.
So let's wrap it into Arc as well. I also don't quite understand why do we need to close the executor when we close the server? It wasn't the case for WS or IPC server?
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.
@tomusdrw, in the current WS implementation, close() also closes the executor: https://github.com/paritytech/jsonrpc/blob/master/ws/src/server.rs#L149
tomusdrw
left a comment
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.
Looks good, please add missing docs and re-format the code using tabs (see .editorconfig file).
Could you also explain why do we need close_handle for Executor and RpcEventLoop?
|
@tomusdrw I added the close_handle in Executor and RpcEventLoop because I wanted to support the following behavior:
Unfortunately, if the CloseHandle just held a reference to a lock to the Executors (as was done in the websockets implementation), b/c the Wait() function also simultaneously needs access to the Executors, this won't work. Thus the close_handle() on the reactor and executor return the inner Complete() signaler that executor->close() would have called anyway, so now the CloseHandle no longer needs shared access/lock to the Executor. |
|
|
||
| /// Returns a handle to the server that can be used to close it while another thread is | ||
| /// blocking in `wait`. | ||
| pub fn close_handle(&mut self) -> CloseHandle { |
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 function shouldn't mutate anything, so it should be &self.
| pub fn close_handle(&mut self) -> CloseHandle { | |
| pub fn close_handle(&self) -> CloseHandle { | |
| let executor_close: Option<Vec<_>> = self.executor.as_ref().map(|executors| { | |
| executors | |
| .iter() | |
| .map(|executor| executor.close_handle()) | |
| .collect() | |
| }); | |
| ... | |
| } |
| } | ||
|
|
||
| /// Returns a handle to close the underlying event loop | ||
| pub fn close_handle(&mut self) -> Option<futures::Complete<()>> { |
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.
mut not needed
| pub fn close_handle(&mut self) -> Option<futures::Complete<()>> { | |
| pub fn close_handle(&self) -> Option<futures::Complete<()>> { |
|
|
||
| /// Returns the close signal that can be used to close the event loop even while | ||
| /// another thread is blocked on the event loop in "wait" | ||
| pub fn close_handle(&mut self) -> Option<futures::Complete<()>>{ |
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.
This function doesn't make much sense - the whole point of handle is to be able to have multiple instance of it.
This function here will take() the close handle and only return it for the first caller. Subsequent calls will always yield None.
What's more it violates the assumption in the rest of this struct (see expect("..") calls) - so every other function like close() or wait() will actually panic.
I still believe that having this function is completely unnecessary. See how it's done in WebSockets server - we own Executor via Arc<Mutex<Option<Executor>>> and close it completely inside CloseHandle (actually it's not perfect there, cause cloning the handle and calling close() on a clone would panic, but it's a separate issue).
| /// jsonrpc http server instance | ||
| pub struct Server { | ||
| address: SocketAddr, | ||
| executor: Option<Vec<Executor>>, |
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.
executor should most likely be wrapped in Arc<Mutex< as wel, so that it can be passed to CloseHandle. Actually it would be simpler to store CloseHandle directly in Server and just clone it when requested. CloseHandle should handle the case if Options are None.
To simplify it further you can just have:
pub struct Server {
address: SocketAddr,
close_handle: CloseHandle,
}
impl Server {
...
pub fn close_handle(&self) -> CloseHandle {
self.close_handle.clone()
}
}
#[derive(Clone)]
pub struct CloseHandle {
handle: Arc<Mutex<Option<(Executor, Vec<oneshot::Sender<()>)>>>,
}
impl CloseHandle {
/// <docs ...>
/// returns `false` if the server was closed earlier
pub fn close(self) -> bool {
if let Some((executor, senders)) = self.handle.lock().take() {
executor.close();
for s in senders { s.send(()).expect(...) }
true
} else { false }
}
}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.
Not sure how this would work: once the server starts waiting it has to take the lock on the handle, so close() as written above will hang on the lock?
|
@tomusdrw The WebSockets server has a separate handle that it joins on in wait(), whereas the wait() implementation in this module requires access to the executor, so we wouldn't be able to call close() on the close handle while another thread is blocked on wait(). Is there a way to construct a similar, separate handle as exists in the WebSockets implementation? |
|
@carllin Indeed WebSockets server runs an extra thread for itself, and in close handle we wait for that thread to finish. With HTTP the proper solution would be to add another Line 461 in 2ed142d
And Server::wait() should actually wait for this, not the entire excutor to be closed.
|
|
@carlin I'd like to get that merged, did you consider implementing my proposed changes? We definitely need to support multiple |
|
Hey Tomas,
Sorry I haven't been able to get to it, I've been swamped with work at
work xD. Hopefully I might have some time closer to vacation time. Thanks
for following up!
Best,
Carl
…On Fri, Dec 7, 2018 at 1:23 AM Tomasz Drwięga ***@***.***> wrote:
@carlin <https://github.com/carlin> I'd like to get that merged, did you
consider implementing my proposed changes? We definitely need to support
multiple CloseHandles`, that's the whole point of having a clonable
handle - otherwise only one handle can be present, cause others will just
panic.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#331 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ADN-z91hK-8FdZLPjPTgGgyaQG19Q-8aks5u2jN2gaJpZM4X2-Eu>
.
|
|
@carllin any chance we can get the changes in? If things have piled up on your end we can perhaps take over and finish it up, just let us know! :) |
|
@dvdplm, sorry don't have much bandwidth nowadays xD. Of somebody could drag this to the finish line that would be highly appreciated :D. Thanks for all the help! |
|
Closing in favour of #437 |
Add CloseHandle to Json Http server to allow a different thread to close() after calling wait() on main server thread. Based on similar work for websockets: https://github.com/paritytech/jsonrpc/pull/151/files