Skip to content

Commit 1bbd403

Browse files
dvdplmtomusdrw
authored andcommitted
Add a way to close the http server while waiting (#437)
* Fix a few compiler warnings * WIP * cleanup * Cleanup and docs * Fix whitespace and grammar * Update http/src/lib.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Now that wait() does not use the eventloop/signalling chans, just bundle them up in a tuple
1 parent 8c0ada4 commit 1bbd403

File tree

6 files changed

+84
-38
lines changed

6 files changed

+84
-38
lines changed

http/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ jsonrpc-server-utils = { version = "11.0", path = "../server-utils" }
1717
log = "0.4"
1818
net2 = "0.2"
1919
unicase = "2.0"
20-
20+
parking_lot = "0.8.0"
2121
[badges]
2222
travis-ci = { repository = "paritytech/jsonrpc", branch = "master"}

http/src/lib.rs

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ use std::net::SocketAddr;
4040
use std::sync::{mpsc, Arc};
4141
use std::thread;
4242

43+
use parking_lot::Mutex;
44+
4345
use crate::jsonrpc::futures::sync::oneshot;
4446
use crate::jsonrpc::futures::{self, future, Future, Stream};
4547
use crate::jsonrpc::MetaIoHandler;
@@ -377,10 +379,12 @@ impl<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>> ServerBuilder<M, S> {
377379

378380
let (local_addr_tx, local_addr_rx) = mpsc::channel();
379381
let (close, shutdown_signal) = oneshot::channel();
382+
let (done_tx, done_rx) = oneshot::channel();
380383
let eloop = self.executor.init_with_name("http.worker0")?;
381384
let req_max_size = self.max_request_body_size;
385+
// The first threads `Executor` is initialised differently from the others
382386
serve(
383-
(shutdown_signal, local_addr_tx),
387+
(shutdown_signal, local_addr_tx, done_tx),
384388
eloop.executor(),
385389
addr.to_owned(),
386390
cors_domains.clone(),
@@ -399,9 +403,10 @@ impl<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>> ServerBuilder<M, S> {
399403
.map(|i| {
400404
let (local_addr_tx, local_addr_rx) = mpsc::channel();
401405
let (close, shutdown_signal) = oneshot::channel();
406+
let (done_tx, done_rx) = oneshot::channel();
402407
let eloop = UninitializedExecutor::Unspawned.init_with_name(format!("http.worker{}", i + 1))?;
403408
serve(
404-
(shutdown_signal, local_addr_tx),
409+
(shutdown_signal, local_addr_tx, done_tx),
405410
eloop.executor(),
406411
addr.to_owned(),
407412
cors_domains.clone(),
@@ -416,27 +421,34 @@ impl<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>> ServerBuilder<M, S> {
416421
reuse_port,
417422
req_max_size,
418423
);
419-
Ok((eloop, close, local_addr_rx))
424+
Ok((eloop, close, local_addr_rx, done_rx))
420425
})
421426
.collect::<io::Result<Vec<_>>>()?;
422427

423428
// Wait for server initialization
424429
let local_addr = recv_address(local_addr_rx);
425430
// Wait for other threads as well.
426-
let mut handles = handles
431+
let mut handles: Vec<(Executor, oneshot::Sender<()>, oneshot::Receiver<()>)> = handles
427432
.into_iter()
428-
.map(|(eloop, close, local_addr_rx)| {
433+
.map(|(eloop, close, local_addr_rx, done_rx)| {
429434
let _ = recv_address(local_addr_rx)?;
430-
Ok((eloop, close))
435+
Ok((eloop, close, done_rx))
431436
})
432437
.collect::<io::Result<(Vec<_>)>>()?;
433-
handles.push((eloop, close));
434-
let (executors, close) = handles.into_iter().unzip();
438+
handles.push((eloop, close, done_rx));
439+
440+
let (executors, done_rxs) = handles
441+
.into_iter()
442+
.fold((vec![], vec![]), |mut acc, (eloop, closer, done_rx)| {
443+
acc.0.push((eloop, closer));
444+
acc.1.push(done_rx);
445+
acc
446+
});
435447

436448
Ok(Server {
437449
address: local_addr?,
438-
executor: Some(executors),
439-
close: Some(close),
450+
executors: Arc::new(Mutex::new(Some(executors))),
451+
done: Some(done_rxs),
440452
})
441453
}
442454
}
@@ -448,7 +460,7 @@ fn recv_address(local_addr_rx: mpsc::Receiver<io::Result<SocketAddr>>) -> io::Re
448460
}
449461

450462
fn serve<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>>(
451-
signals: (oneshot::Receiver<()>, mpsc::Sender<io::Result<SocketAddr>>),
463+
signals: (oneshot::Receiver<()>, mpsc::Sender<io::Result<SocketAddr>>, oneshot::Sender<()>),
452464
executor: tokio::runtime::TaskExecutor,
453465
addr: SocketAddr,
454466
cors_domains: CorsDomains,
@@ -463,7 +475,7 @@ fn serve<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>>(
463475
reuse_port: bool,
464476
max_request_body_size: usize,
465477
) {
466-
let (shutdown_signal, local_addr_tx) = signals;
478+
let (shutdown_signal, local_addr_tx, done_tx) = signals;
467479
executor.spawn(future::lazy(move || {
468480
let handle = tokio::reactor::Handle::default();
469481

@@ -537,12 +549,15 @@ fn serve<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>>(
537549
.map_err(|e| {
538550
warn!("Incoming streams error, closing sever: {:?}", e);
539551
})
540-
.select(shutdown_signal.map_err(|e| {
552+
.select(shutdown_signal
553+
.map_err(|e| {
541554
debug!("Shutdown signaller dropped, closing server: {:?}", e);
542555
}))
543556
.map(|_| ())
544557
.map_err(|_| ())
545558
})
559+
}).and_then(|_| {
560+
done_tx.send(())
546561
}));
547562
}
548563

@@ -562,45 +577,60 @@ fn configure_port(_reuse: bool, _tcp: &net2::TcpBuilder) -> io::Result<()> {
562577
Ok(())
563578
}
564579

580+
/// Handle used to close the server. Can be cloned and passed around to different threads and be used
581+
/// to close a server that is `wait()`ing.
582+
583+
#[derive(Clone)]
584+
pub struct CloseHandle(Arc<Mutex<Option<Vec<(Executor, oneshot::Sender<()>)>>>>);
585+
586+
impl CloseHandle {
587+
/// Shutdown a running server
588+
pub fn close(self) {
589+
if let Some(executors) = self.0.lock().take() {
590+
for (executor, closer) in executors {
591+
executor.close();
592+
let _ = closer.send(());
593+
}
594+
}
595+
}
596+
}
597+
565598
/// jsonrpc http server instance
566599
pub struct Server {
567600
address: SocketAddr,
568-
executor: Option<Vec<Executor>>,
569-
close: Option<Vec<oneshot::Sender<()>>>,
601+
executors: Arc<Mutex<Option<Vec<(Executor, oneshot::Sender<()>)>>>>,
602+
done: Option<Vec<oneshot::Receiver<()>>>,
570603
}
571604

572-
const PROOF: &str = "Server is always Some until self is consumed.";
573605
impl Server {
574606
/// Returns address of this server
575607
pub fn address(&self) -> &SocketAddr {
576608
&self.address
577609
}
578610

579611
/// Closes the server.
580-
pub fn close(mut self) {
581-
for close in self.close.take().expect(PROOF) {
582-
let _ = close.send(());
583-
}
584-
585-
for executor in self.executor.take().expect(PROOF) {
586-
executor.close();
587-
}
612+
pub fn close(self) {
613+
self.close_handle().close()
588614
}
589615

590616
/// Will block, waiting for the server to finish.
591617
pub fn wait(mut self) {
592-
for executor in self.executor.take().expect(PROOF) {
593-
executor.wait();
618+
if let Some(receivers) = self.done.take() {
619+
for receiver in receivers {
620+
let _ = receiver.wait();
621+
}
594622
}
595623
}
624+
625+
/// Get a handle that allows us to close the server from a different thread and/or while the
626+
/// server is `wait()`ing.
627+
pub fn close_handle(&self) -> CloseHandle {
628+
CloseHandle(self.executors.clone())
629+
}
596630
}
597631

598632
impl Drop for Server {
599633
fn drop(&mut self) {
600-
if let Some(executors) = self.executor.take() {
601-
for executor in executors {
602-
executor.close();
603-
}
604-
};
634+
self.close_handle().close();
605635
}
606636
}

http/src/tests.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use self::jsonrpc_core::{Error, ErrorCode, IoHandler, Params, Value};
44
use std::io::{Read, Write};
55
use std::net::TcpStream;
66
use std::str::Lines;
7+
use std::time::Duration;
78

89
use self::jsonrpc_core::futures::{self, Future};
910
use super::*;
@@ -52,8 +53,6 @@ fn serve_allow_headers(cors_allow_headers: cors::AccessControlAllowHeaders) -> S
5253
}
5354

5455
fn io() -> IoHandler {
55-
use std::{thread, time};
56-
5756
let mut io = IoHandler::default();
5857
io.add_method("hello", |params: Params| match params.parse::<(u64,)>() {
5958
Ok((num,)) => Ok(Value::String(format!("world: {}", num))),
@@ -66,7 +65,7 @@ fn io() -> IoHandler {
6665
io.add_method("hello_async2", |_params: Params| {
6766
let (c, p) = futures::oneshot();
6867
thread::spawn(move || {
69-
thread::sleep(time::Duration::from_millis(10));
68+
thread::sleep(Duration::from_millis(10));
7069
c.send(Value::String("world".into())).unwrap();
7170
});
7271
p.map_err(|_| Error::invalid_request())
@@ -1406,6 +1405,24 @@ fn should_return_connection_header() {
14061405
assert_eq!(response.body, world_batch());
14071406
}
14081407

1408+
#[test]
1409+
fn close_handle_makes_wait_return() {
1410+
let server = serve(id);
1411+
let close_handle = server.close_handle();
1412+
1413+
let (tx, rx) = mpsc::channel();
1414+
1415+
thread::spawn(move || {
1416+
tx.send(server.wait()).unwrap();
1417+
});
1418+
1419+
thread::sleep(Duration::from_secs(3));
1420+
1421+
close_handle.close();
1422+
1423+
rx.recv_timeout(Duration::from_secs(10)).expect("Expected server to close");
1424+
}
1425+
14091426
#[test]
14101427
fn should_close_connection_without_keep_alive() {
14111428
// given

ipc/src/logger.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ lazy_static! {
1010
builder.filter(None, LevelFilter::Info);
1111

1212
if let Ok(log) = env::var("RUST_LOG") {
13-
builder.parse(&log);
13+
builder.parse_filters(&log);
1414
}
1515

1616
if let Ok(_) = builder.try_init() {

tcp/src/logger.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ lazy_static! {
88
builder.filter(None, LevelFilter::Info);
99

1010
if let Ok(log) = env::var("RUST_LOG") {
11-
builder.parse(&log);
11+
builder.parse_filters(&log);
1212
}
1313

1414
if let Ok(_) = builder.try_init() {

ws/src/tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ fn request(server: Server, request: &str) -> Response {
6262

6363
fn serve(port: u16) -> (Server, Arc<AtomicUsize>) {
6464
use crate::core::futures::sync::oneshot;
65-
use std::time::Duration;
6665

6766
let pending = Arc::new(AtomicUsize::new(0));
6867

0 commit comments

Comments
 (0)