Integrates signal handling with lifecycle
Refactors the application shutdown mechanism to use lifecycle commands. OS signals (SIGTERM/SIGINT) now sends a `Dying` command directly to the brain. The brain processes this command, transitioning through `Dying` to `Buried` state. The main loop now explicitly waits for the brain to report a `Dead` or `Buried` state before exiting, ensuring a graceful shutdown. Increases the brain's rest duration and adds debug logging.
This commit is contained in:
parent
500b26703e
commit
58e1197ff4
3 changed files with 41 additions and 15 deletions
|
|
@ -1 +1 @@
|
||||||
136
|
140
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use tracing::info;
|
use tracing::{debug, info};
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleCommandResponse, LifecycleReceipt};
|
use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleCommandResponse, LifecycleReceipt};
|
||||||
use crate::lifecycle::LifeState::{Buried, Genisys};
|
use crate::lifecycle::LifeState::{Dying, Buried, Genisys};
|
||||||
|
|
||||||
pub struct Brain {
|
pub struct Brain {
|
||||||
state:LifeState,
|
state:LifeState,
|
||||||
|
|
@ -36,14 +36,22 @@ impl Brain {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rest() {
|
fn rest() {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1))
|
debug!("Brain is resting.");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_divine_command(&mut self, command: LifecycleCommand) {
|
fn handle_divine_command(&mut self, command: LifecycleCommand) {
|
||||||
info!("God has commanded {:?}", command);
|
info!("God has commanded {:?}", command);
|
||||||
|
|
||||||
if self.can_transition_lifecycle(&command) {
|
if self.can_transition_lifecycle(&command) {
|
||||||
self.set_lifecycle_state(&command);
|
if command.required_state == Dying
|
||||||
|
{
|
||||||
|
self.set_lifecycle_state(&command, Buried);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
self.set_lifecycle_state(&command, command.required_state);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,7 +68,7 @@ impl Brain {
|
||||||
fn can_transition_lifecycle(&self, command: &LifecycleCommand) -> bool
|
fn can_transition_lifecycle(&self, command: &LifecycleCommand) -> bool
|
||||||
{
|
{
|
||||||
|
|
||||||
if (command.required_state == Buried) {
|
if command.required_state == Buried || command.required_state == Dying {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,17 +78,19 @@ impl Brain {
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
fn set_lifecycle_state(&mut self, command: &LifecycleCommand) {
|
fn set_lifecycle_state(&mut self, command: &LifecycleCommand, new_state: LifeState) {
|
||||||
self.state = command.required_state;
|
self.state = new_state;
|
||||||
self.report_to_god(LifecycleReceipt{
|
self.report_to_god(LifecycleReceipt{
|
||||||
command: command.clone(),
|
command: command.clone(),
|
||||||
response: LifecycleCommandResponse::Ok,
|
response: LifecycleCommandResponse::Ok,
|
||||||
new_state: self.state
|
new_state: self.state
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_to_god(&self, receipt: LifecycleReceipt) {
|
fn report_to_god(&self, receipt: LifecycleReceipt) {
|
||||||
info!("Reporting to God: Status = {:?}, NewState={:?}", receipt.response, receipt.new_state);
|
info!("Reporting to God: Status = {:?}, NewState={:?}", receipt.response, receipt.new_state);
|
||||||
let _ = self.divine_tx.send(receipt);
|
let _ = self.divine_tx.send(receipt);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,40 @@
|
||||||
pub mod lifecycle;
|
pub mod lifecycle;
|
||||||
pub mod brain;
|
pub mod brain;
|
||||||
|
|
||||||
use tracing::info;
|
use std::fmt::Alignment::Left;
|
||||||
|
use tracing::{info, debug};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
use tracing_subscriber::registry;
|
||||||
use crate::brain::Brain;
|
use crate::brain::Brain;
|
||||||
use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleReceipt};
|
use crate::lifecycle::{LifeState, LifecycleCommand, LifecycleReceipt};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let shutdown_requested = Arc::new(AtomicBool::new(false));
|
|
||||||
|
|
||||||
setup_logging();
|
setup_logging();
|
||||||
info!("RustyLee: {}", env!("FULL_VERSION"));
|
info!("RustyLee: {}", env!("FULL_VERSION"));
|
||||||
|
|
||||||
setup_os_signal_handler(shutdown_requested.clone());
|
|
||||||
let (tx, rx) = spawn_brain();
|
let (tx, rx) = spawn_brain();
|
||||||
|
setup_os_signal_handler(tx.clone());
|
||||||
let_there_be_life(&tx, &rx);
|
let_there_be_life(&tx, &rx);
|
||||||
wait_for_death(tx, rx);
|
|
||||||
|
info!("God is watching.");
|
||||||
|
loop{
|
||||||
|
if let Ok(receipt) = rx.recv() {
|
||||||
|
debug!("Brain status: {:?}", receipt.new_state);
|
||||||
|
|
||||||
|
if receipt.new_state == LifeState::Dead || receipt.new_state == LifeState::Buried {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// wait_for_death(tx, rx);
|
||||||
|
|
||||||
info!("God: Brain has been buried. Shutting down.");
|
info!("God: Brain has been buried. Shutting down.");
|
||||||
}
|
}
|
||||||
|
|
@ -69,11 +82,14 @@ fn spawn_brain() -> (Sender<LifecycleCommand>, Receiver<LifecycleReceipt>) {
|
||||||
(to_brain_tx, from_brain_rx)
|
(to_brain_tx, from_brain_rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_os_signal_handler(s: Arc<AtomicBool>) {
|
fn setup_os_signal_handler(tx: Sender<LifecycleCommand>) {
|
||||||
info!("Setting up SIGTERM/SIGINT handling.");
|
info!("Setting up SIGTERM/SIGINT handling.");
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
info!("[Signal] Shutdown signal caught!");
|
info!("[Signal] Shutdown signal caught!");
|
||||||
s.store(true, Ordering::SeqCst);
|
let _ = tx.send(LifecycleCommand {
|
||||||
|
required_state: LifeState::Dying,
|
||||||
|
command_time: Instant::now(),
|
||||||
|
});
|
||||||
}).expect("Error setting signal handler.");
|
}).expect("Error setting signal handler.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue