node: exit on GRANDPA voter or BABE authoring error (#3353)

* node: exit on GRANDPA voter or BABE authoring error

* node: exit process with non-zero return code when service fails

* service: rename infallible task to essential task

* service: revert field name changes

* core: fix service testnet
This commit is contained in:
André Silva
2019-08-12 14:54:30 +01:00
committed by Robert Habermeier
parent 09b57261df
commit 70d716dc48
10 changed files with 98 additions and 41 deletions
+2 -2
View File
@@ -502,7 +502,7 @@ impl<Factory: ServiceFactory> DerefMut for FullComponents<Factory> {
impl<Factory: ServiceFactory> Future for FullComponents<Factory> {
type Item = ();
type Error = ();
type Error = super::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.service.poll()
@@ -627,7 +627,7 @@ impl<Factory: ServiceFactory> DerefMut for LightComponents<Factory> {
impl<Factory: ServiceFactory> Future for LightComponents<Factory> {
type Item = ();
type Error = ();
type Error = super::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.service.poll()
+28 -3
View File
@@ -28,6 +28,7 @@ pub mod error;
use std::io;
use std::net::SocketAddr;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
use futures::sync::mpsc;
use parking_lot::Mutex;
@@ -82,8 +83,14 @@ pub struct Service<Components: components::Components> {
NetworkStatus<ComponentBlock<Components>>, NetworkState
)>>>>,
transaction_pool: Arc<TransactionPool<Components::TransactionPoolApi>>,
/// A future that resolves when the service has exited, this is useful to
/// make sure any internally spawned futures stop when the service does.
exit: exit_future::Exit,
/// A signal that makes the exit future above resolve, fired on service drop.
signal: Option<Signal>,
/// Set to `true` when a spawned essential task has failed. The next time
/// the service future is polled it should complete with an error.
essential_failed: Arc<AtomicBool>,
/// Sender for futures that must be spawned as background tasks.
to_spawn_tx: mpsc::UnboundedSender<Box<dyn Future<Item = (), Error = ()> + Send>>,
/// Receiver for futures that must be spawned as background tasks.
@@ -395,7 +402,7 @@ impl<Components: components::Components> Service<Components> {
// Telemetry
let telemetry = config.telemetry_endpoints.clone().map(|endpoints| {
let is_authority = config.roles == Roles::AUTHORITY;
let is_authority = config.roles.is_authority();
let network_id = network.local_peer_id().to_base58();
let name = config.name.clone();
let impl_name = config.impl_name.to_owned();
@@ -440,12 +447,13 @@ impl<Components: components::Components> Service<Components> {
network_status_sinks,
select_chain,
transaction_pool,
exit,
signal: Some(signal),
essential_failed: Arc::new(AtomicBool::new(false)),
to_spawn_tx,
to_spawn_rx,
to_poll: Vec::new(),
config,
exit,
rpc_handlers,
_rpc: rpc,
_telemetry: telemetry,
@@ -491,6 +499,19 @@ impl<Components: components::Components> Service<Components> {
let _ = self.to_spawn_tx.unbounded_send(Box::new(task));
}
/// Spawns a task in the background that runs the future passed as
/// parameter. The given task is considered essential, i.e. if it errors we
/// trigger a service exit.
pub fn spawn_essential_task(&self, task: impl Future<Item = (), Error = ()> + Send + 'static) {
let essential_failed = self.essential_failed.clone();
let essential_task = Box::new(task.map_err(move |_| {
error!("Essential task failed. Shutting down service.");
essential_failed.store(true, Ordering::Relaxed);
}));
let _ = self.to_spawn_tx.unbounded_send(essential_task);
}
/// Returns a handle for spawning tasks.
pub fn spawn_task_handle(&self) -> SpawnTaskHandle {
SpawnTaskHandle {
@@ -548,9 +569,13 @@ impl<Components: components::Components> Service<Components> {
impl<Components> Future for Service<Components> where Components: components::Components {
type Item = ();
type Error = ();
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if self.essential_failed.load(Ordering::Relaxed) {
return Err(Error::Other("Essential task failed.".into()));
}
while let Ok(Async::Ready(Some(task_to_spawn))) = self.to_spawn_rx.poll() {
let executor = tokio_executor::DefaultExecutor::current();
if let Err(err) = executor.execute(task_to_spawn) {