Problem: intentional bridge shutdowns
It is impossible to tell whether the bridge is being shut down intentionally or because of an error. This is particularly important for supervising the process, both in development and production. Solution: handle SIGINT and SIGTERM as a special case and designate a separate status code (3) for intentional shutdowns. Also, include an example supervisor for development mode (examples/suprevisor). Simply prepend it before the invocation of bridge to supervise it.
This commit is contained in:
parent
103af3e3fa
commit
38e1cac265
|
@ -44,6 +44,11 @@ dependencies = [
|
|||
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.1"
|
||||
|
@ -78,6 +83,7 @@ name = "bridge-cli"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bridge 0.1.0",
|
||||
"ctrlc 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -116,6 +122,16 @@ name = "crunchy"
|
|||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "1.0.0"
|
||||
|
@ -459,6 +475,17 @@ dependencies = [
|
|||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.12"
|
||||
|
@ -980,12 +1007,14 @@ dependencies = [
|
|||
"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"
|
||||
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
|
||||
"checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||
"checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9"
|
||||
"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
|
||||
"checksum ctrlc 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "653abc99aa905f693d89df4797fadc08085baee379db92be9f2496cefe8a6f2c"
|
||||
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
|
||||
"checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
|
@ -1022,6 +1051,7 @@ dependencies = [
|
|||
"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
|
||||
"checksum nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
"checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10"
|
||||
|
|
|
@ -7,6 +7,9 @@ use error::{Error, ResultExt, ErrorKind};
|
|||
use config::Config;
|
||||
use contracts::{home, foreign};
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
pub struct App<T> where T: Transport {
|
||||
pub config: Config,
|
||||
pub database_path: PathBuf,
|
||||
|
@ -14,6 +17,7 @@ pub struct App<T> where T: Transport {
|
|||
pub home_bridge: home::HomeBridge,
|
||||
pub foreign_bridge: foreign::ForeignBridge,
|
||||
pub timer: Timer,
|
||||
pub running: Arc<AtomicBool>
|
||||
}
|
||||
|
||||
pub struct Connections<T> where T: Transport {
|
||||
|
@ -50,7 +54,7 @@ impl<T: Transport> Connections<T> {
|
|||
}
|
||||
|
||||
impl App<Ipc> {
|
||||
pub fn new_ipc<P: AsRef<Path>>(config: Config, database_path: P, handle: &Handle) -> Result<Self, Error> {
|
||||
pub fn new_ipc<P: AsRef<Path>>(config: Config, database_path: P, handle: &Handle, running: Arc<AtomicBool>) -> Result<Self, Error> {
|
||||
let connections = Connections::new_ipc(handle, &config.home.ipc, &config.foreign.ipc)?;
|
||||
let result = App {
|
||||
config,
|
||||
|
@ -59,6 +63,7 @@ impl App<Ipc> {
|
|||
home_bridge: home::HomeBridge::default(),
|
||||
foreign_bridge: foreign::ForeignBridge::default(),
|
||||
timer: Timer::default(),
|
||||
running,
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -73,6 +78,7 @@ impl<T: Transport> App<T> {
|
|||
home_bridge: home::HomeBridge::default(),
|
||||
foreign_bridge: foreign::ForeignBridge::default(),
|
||||
timer: self.timer.clone(),
|
||||
running: self.running.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use futures::{Stream, Poll, Async};
|
|||
use web3::Transport;
|
||||
use app::App;
|
||||
use database::Database;
|
||||
use error::{Error, Result};
|
||||
use error::{Error, ErrorKind, Result};
|
||||
|
||||
pub use self::deploy::{Deploy, Deployed, create_deploy};
|
||||
pub use self::deposit_relay::{DepositRelay, create_deposit_relay};
|
||||
|
@ -82,6 +82,7 @@ pub fn create_bridge_backed_by<T: Transport + Clone, F: BridgeBackend>(app: Arc<
|
|||
withdraw_confirm: create_withdraw_confirm(app.clone(), init),
|
||||
state: BridgeStatus::Wait,
|
||||
backend,
|
||||
running: app.running.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,8 +92,11 @@ pub struct Bridge<T: Transport, F> {
|
|||
withdraw_confirm: WithdrawConfirm<T>,
|
||||
state: BridgeStatus,
|
||||
backend: F,
|
||||
running: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
impl<T: Transport, F: BridgeBackend> Stream for Bridge<T, F> {
|
||||
type Item = ();
|
||||
type Error = Error;
|
||||
|
@ -101,6 +105,9 @@ impl<T: Transport, F: BridgeBackend> Stream for Bridge<T, F> {
|
|||
loop {
|
||||
let next_state = match self.state {
|
||||
BridgeStatus::Wait => {
|
||||
if !self.running.load(Ordering::SeqCst) {
|
||||
return Err(ErrorKind::ShutdownRequested.into())
|
||||
}
|
||||
let d_relay = try_bridge!(self.deposit_relay.poll()).map(BridgeChecked::DepositRelay);
|
||||
let w_relay = try_bridge!(self.withdraw_relay.poll()).map(BridgeChecked::WithdrawRelay);
|
||||
let w_confirm = try_bridge!(self.withdraw_confirm.poll()).map(BridgeChecked::WithdrawConfirm);
|
||||
|
|
|
@ -19,6 +19,7 @@ error_chain! {
|
|||
}
|
||||
|
||||
errors {
|
||||
ShutdownRequested
|
||||
// api timeout
|
||||
Timeout(request: &'static str) {
|
||||
description("Request timeout"),
|
||||
|
|
|
@ -16,3 +16,4 @@ docopt = "0.8.1"
|
|||
log = "0.3"
|
||||
env_logger = "0.4"
|
||||
futures = "0.1.14"
|
||||
ctrlc = { version = "3.1", features = ["termination"] }
|
||||
|
|
|
@ -8,6 +8,7 @@ extern crate tokio_core;
|
|||
extern crate log;
|
||||
extern crate env_logger;
|
||||
extern crate bridge;
|
||||
extern crate ctrlc;
|
||||
|
||||
use std::{env, fs, io};
|
||||
use std::sync::Arc;
|
||||
|
@ -24,6 +25,7 @@ use bridge::web3;
|
|||
|
||||
const ERR_UNKNOWN: i32 = 1;
|
||||
const ERR_IO_ERROR: i32 = 2;
|
||||
const ERR_SHUTDOWN_REQUESTED: i32 = 3;
|
||||
const ERR_CANNOT_CONNECT: i32 = 10;
|
||||
const ERR_CONNECTION_LOST: i32 = 11;
|
||||
const ERR_BRIDGE_CRASH: i32 = 11;
|
||||
|
@ -75,9 +77,19 @@ pub struct Args {
|
|||
arg_database: PathBuf,
|
||||
}
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
fn main() {
|
||||
let _ = env_logger::init();
|
||||
let result = execute(env::args());
|
||||
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
|
||||
let r = running.clone();
|
||||
ctrlc::set_handler(move || {
|
||||
r.store(false, Ordering::SeqCst);
|
||||
}).expect("Error setting Ctrl-C handler");
|
||||
|
||||
let result = execute(env::args(), running);
|
||||
|
||||
match result {
|
||||
Ok(s) => println!("{}", s),
|
||||
|
@ -94,7 +106,7 @@ fn print_err(err: Error) {
|
|||
println!("{}", message);
|
||||
}
|
||||
|
||||
fn execute<S, I>(command: I) -> Result<String, UserFacingError> where I: IntoIterator<Item=S>, S: AsRef<str> {
|
||||
fn execute<S, I>(command: I, running: Arc<AtomicBool>) -> Result<String, UserFacingError> where I: IntoIterator<Item=S>, S: AsRef<str> {
|
||||
info!(target: "bridge", "Parsing cli arguments");
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
.and_then(|d| d.argv(command).deserialize()).map_err(|e| e.to_string())?;
|
||||
|
@ -106,7 +118,7 @@ fn execute<S, I>(command: I) -> Result<String, UserFacingError> where I: IntoIte
|
|||
let mut event_loop = Core::new().unwrap();
|
||||
|
||||
info!(target: "bridge", "Establishing ipc connection");
|
||||
let app = match App::new_ipc(config.clone(), &args.arg_database, &event_loop.handle()) {
|
||||
let app = match App::new_ipc(config.clone(), &args.arg_database, &event_loop.handle(), running) {
|
||||
Ok(app) => app,
|
||||
Err(e) => {
|
||||
warn!("Can't establish an IPC connection: {:?}", e);
|
||||
|
@ -144,6 +156,10 @@ fn execute<S, I>(command: I) -> Result<String, UserFacingError> where I: IntoIte
|
|||
return Err((ERR_IO_ERROR, e.into()).into());
|
||||
}
|
||||
},
|
||||
Err(e @ Error(ErrorKind::ShutdownRequested, _)) => {
|
||||
info!("Shutdown requested, terminating");
|
||||
return Err((ERR_SHUTDOWN_REQUESTED, e.into()).into());
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Bridge crashed with {}", e);
|
||||
return Err((ERR_BRIDGE_CRASH, e).into());
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
while true; do
|
||||
"$@"
|
||||
if [ $? == 3 ]; then
|
||||
# shutdown requested by user
|
||||
echo "Shutting down"
|
||||
exit 0
|
||||
fi
|
||||
echo "Restarting after 1 second"
|
||||
sleep 1
|
||||
done
|
Loading…
Reference in New Issue