Files
rustybeds/src/main.rs
gramps c1d1ff14a5 Add RabbitMQ validation, test scaffolding, and config refactor
- Extract ipl() from main() with env-aware error handling (fatal in prod, warn in dev)
- Add amqp::validate() — TCP reachability check for RabbitMQ at IPL
- Refactor config::load() into load() + load_from() for testability
- Add lib.rs to expose public API to integration test harness
- Add test fixture scaffolding: tests/fixtures/beds_test.toml, tests/common/mod.rs
- Add unit tests for amqp::validate() error paths (closed port, bad address)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:32:24 -07:00

81 lines
2.6 KiB
Rust

//! # main.rs — BEDS Entry Point
//!
//! Application entry point. Invokes the IPL (Initial Program Load) sequence
//! which bootstraps all required services before the node enters its
//! operational state.
//!
//! ## Calling Agents
//! None — this is the process entry point.
//!
//! ## Inputs
//! - `BEDS_ENV` environment variable selects the env config file (default: dev)
//!
//! ## Outputs
//! - Running BEDS node, blocked on signal handler (not yet implemented)
//! - On fatal IPL failure: error output to console, process exits non-zero
//!
//! **Author:** ms
//! **Version:** 1.0
//!
//! ## History
//! * `2026-04-02` - mks - original coding
//! * `2026-04-02` - mks - refactored startup sequence into ipl()
mod amqp;
mod config;
mod logging;
/// Executes the BEDS Initial Program Load (IPL) sequence.
///
/// IPL bootstraps the node in strict order. Each step must succeed before
/// the next is attempted. In production environments, any failure is fatal
/// and the process exits with a console error report. In development
/// environments, non-critical failures are logged and IPL continues.
///
/// ## IPL Sequence
/// 1. Load configuration (beds.toml + env override)
/// 2. Initialize logging
/// 3. Connect to required services (AMQP, store adapters) — not yet implemented
/// 4. Declare queues based on node role — not yet implemented
/// 5. Node green
///
/// # Returns
///
/// `Ok(())` if all required services are available and the node is ready.
/// `Err(String)` with a descriptive error message if IPL cannot complete.
///
/// # History
///
/// * `2026-04-02` - mks - original coding
fn ipl() -> Result<(), String> {
// load configuration — fatal in all environments if this fails
let cfg = config::load().map_err(|e| format!("Failed to load config: {}", e))?;
// initialize logging — must come before any tracing calls
logging::init_from_config(cfg.syslog, cfg.syslog_mirror_console);
tracing::info!("BEDS IPL starting, node={} env={}", cfg.id.wbid, cfg.id.env_name);
tracing::info!("Configuration loaded");
tracing::info!("Logging initialized");
// validate broker reachability — fatal in production, non-fatal in all other envs
match amqp::validate(&cfg.broker_services) {
Ok(()) => tracing::info!("RabbitMQ reachable"),
Err(e) => {
if cfg.id.env_name == "production" {
return Err(e);
}
tracing::warn!("RabbitMQ unreachable (non-fatal in {}): {}", cfg.id.env_name, e);
}
}
Ok(())
}
fn main() {
if let Err(e) = ipl() {
eprintln!("[BEDS] [FATAL] [IPL] {}", e);
std::process::exit(1);
}
}