Merge pull request #638 from ethcore/jsonrpc_panic_handle
jsonrpc panics gracefully shutdown client
This commit is contained in:
		
						commit
						02b23d3deb
					
				| @ -385,7 +385,7 @@ impl BlockQueue { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn collect_garbage(&self) { 
 | ||||
| 	pub fn collect_garbage(&self) { | ||||
| 		{ | ||||
| 			let mut verification = self.verification.lock().unwrap(); | ||||
| 			verification.unverified.shrink_to_fit(); | ||||
|  | ||||
| @ -43,7 +43,7 @@ use std::path::PathBuf; | ||||
| use env_logger::LogBuilder; | ||||
| use ctrlc::CtrlC; | ||||
| use util::*; | ||||
| use util::panics::MayPanic; | ||||
| use util::panics::{MayPanic, ForwardPanic, PanicHandler}; | ||||
| use ethcore::spec::*; | ||||
| use ethcore::client::*; | ||||
| use ethcore::service::{ClientService, NetSyncMessage}; | ||||
| @ -190,7 +190,7 @@ fn setup_log(init: &Option<String>) { | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "rpc")] | ||||
| fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>, url: &str, cors_domain: &str, apis: Vec<&str>) { | ||||
| fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>, url: &str, cors_domain: &str, apis: Vec<&str>) -> Option<Arc<PanicHandler>> { | ||||
| 	use rpc::v1::*; | ||||
| 
 | ||||
| 	let mut server = rpc::HttpServer::new(1); | ||||
| @ -207,11 +207,12 @@ fn setup_rpc_server(client: Arc<Client>, sync: Arc<EthSync>, url: &str, cors_dom | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	server.start_async(url, cors_domain); | ||||
| 	Some(server.start_async(url, cors_domain)) | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "rpc"))] | ||||
| fn setup_rpc_server(_client: Arc<Client>, _sync: Arc<EthSync>, _url: &str) { | ||||
| fn setup_rpc_server(_client: Arc<Client>, _sync: Arc<EthSync>, _url: &str) -> Option<Arc<PanicHandler>> { | ||||
| 	None | ||||
| } | ||||
| 
 | ||||
| fn print_version() { | ||||
| @ -340,6 +341,9 @@ impl Configuration { | ||||
| 	} | ||||
| 
 | ||||
| 	fn execute_client(&self) { | ||||
| 		// Setup panic handler
 | ||||
| 		let panic_handler = PanicHandler::new_in_arc(); | ||||
| 
 | ||||
| 		// Setup logging
 | ||||
| 		setup_log(&self.args.flag_logging); | ||||
| 		// Raise fdlimit
 | ||||
| @ -366,6 +370,7 @@ impl Configuration { | ||||
| 		client_config.name = self.args.flag_identity.clone(); | ||||
| 		client_config.queue.max_mem_use = self.args.flag_queue_max_size; | ||||
| 		let mut service = ClientService::start(client_config, spec, net_settings, &Path::new(&self.path())).unwrap(); | ||||
| 		panic_handler.forward_from(&service); | ||||
| 		let client = service.client().clone(); | ||||
| 		client.set_author(self.author()); | ||||
| 		client.set_extra_data(self.extra_data()); | ||||
| @ -383,30 +388,36 @@ impl Configuration { | ||||
| 			let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); | ||||
| 			// TODO: use this as the API list.
 | ||||
| 			let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); | ||||
| 			setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect()); | ||||
| 			let server_handler = setup_rpc_server(service.client(), sync.clone(), &url, cors, apis.split(",").collect()); | ||||
| 			if let Some(handler) = server_handler { | ||||
| 				panic_handler.forward_from(handler.deref()); | ||||
| 			} | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		// Register IO handler
 | ||||
| 		let io_handler  = Arc::new(ClientIoHandler { | ||||
| 			client: service.client(), | ||||
| 			info: Default::default(), | ||||
| 			sync: sync | ||||
| 			sync: sync.clone(), | ||||
| 		}); | ||||
| 		service.io().register_handler(io_handler).expect("Error registering IO handler"); | ||||
| 
 | ||||
| 		// Handle exit
 | ||||
| 		wait_for_exit(&service); | ||||
| 		wait_for_exit(panic_handler); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn wait_for_exit(client_service: &ClientService) { | ||||
| fn wait_for_exit(panic_handler: Arc<PanicHandler>) { | ||||
| 	let exit = Arc::new(Condvar::new()); | ||||
| 
 | ||||
| 	// Handle possible exits
 | ||||
| 	let e = exit.clone(); | ||||
| 	CtrlC::set_handler(move || { e.notify_all(); }); | ||||
| 
 | ||||
| 	// Handle panics
 | ||||
| 	let e = exit.clone(); | ||||
| 	client_service.on_panic(move |_reason| { e.notify_all(); }); | ||||
| 	panic_handler.on_panic(move |_reason| { e.notify_all(); }); | ||||
| 
 | ||||
| 	// Wait for signal
 | ||||
| 	let mutex = Mutex::new(()); | ||||
|  | ||||
| @ -29,6 +29,9 @@ extern crate ethcore; | ||||
| extern crate ethsync; | ||||
| extern crate transient_hashmap; | ||||
| 
 | ||||
| use std::sync::Arc; | ||||
| use std::thread; | ||||
| use util::panics::PanicHandler; | ||||
| use self::jsonrpc_core::{IoHandler, IoDelegate}; | ||||
| 
 | ||||
| pub mod v1; | ||||
| @ -36,7 +39,7 @@ pub mod v1; | ||||
| /// Http server.
 | ||||
| pub struct HttpServer { | ||||
| 	handler: IoHandler, | ||||
| 	threads: usize | ||||
| 	threads: usize, | ||||
| } | ||||
| 
 | ||||
| impl HttpServer { | ||||
| @ -44,7 +47,7 @@ impl HttpServer { | ||||
| 	pub fn new(threads: usize) -> HttpServer { | ||||
| 		HttpServer { | ||||
| 			handler: IoHandler::new(), | ||||
| 			threads: threads | ||||
| 			threads: threads, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -53,9 +56,18 @@ impl HttpServer { | ||||
| 		self.handler.add_delegate(delegate); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Start server asynchronously in new thread
 | ||||
| 	pub fn start_async(self, addr: &str, cors_domain: &str) { | ||||
| 	/// Start server asynchronously in new thread and returns panic handler.
 | ||||
| 	pub fn start_async(self, addr: &str, cors_domain: &str) -> Arc<PanicHandler> { | ||||
| 		let addr = addr.to_owned(); | ||||
| 		let cors_domain = cors_domain.to_owned(); | ||||
| 		let panic_handler = PanicHandler::new_in_arc(); | ||||
| 		let ph = panic_handler.clone(); | ||||
| 		let server = jsonrpc_http_server::Server::new(self.handler, self.threads); | ||||
| 		server.start_async(addr, jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain.to_owned())) | ||||
| 		thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { | ||||
| 			ph.catch_panic(move || { | ||||
| 				server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain)); | ||||
| 			}).unwrap() | ||||
| 		}).expect("Error while creating jsonrpc http thread"); | ||||
| 		panic_handler | ||||
| 	} | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user