summaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-28 05:45:29 +0100
committertv <tv@krebsco.de>2026-10-28 05:45:29 +0100
commitdd0e4a5120751d8dcb4b42834881f36de17ec168 (patch)
tree14a6019984ca6eec0d9d99aead44b039b7d456b6 /src/main.rs
parenta0152151a89035846d564231a4c0023b31dddc0e (diff)
start API earlier
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs50
1 files changed, 31 insertions, 19 deletions
diff --git a/src/main.rs b/src/main.rs
index 3bdf0ed..8a61200 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,6 +5,7 @@
use std::future::IntoFuture;
use std::sync::Arc;
+use std::sync::atomic::{AtomicBool, Ordering};
use anyhow::{Context, Result};
use automerge::AutoCommit;
@@ -314,24 +315,9 @@ async fn main() -> Result<()> {
node.spawn_workers();
- let joining = bootstrap::bootstrap(&state, &seeds, start);
- tokio::select! {
- joined = joining => joined.context("Joining swarm")?,
- _ = stopped(stop.clone()) => {
- info!("Stopped while joining the swarm");
- return Ok(());
- }
- }
-
- node::spawn_ready_workers(&state);
-
- info!(
- swarm_id = ?state.swarm_id().await,
- ready = state.is_ready().await,
- "Bootstrap completed"
- );
- swarm::state_file::update(&state, true).await;
-
+ // The API is up while the node joins: what it serves then is the handlers' business
+ // (`docs/lifecycle.md`), and /peers and /admin/stats show how joining goes.
+ let joined = AtomicBool::new(false);
let app = api::router(state.clone(), auth_state, args.debug_api);
let listener = tokio::net::TcpListener::bind(args.bind_addr)
@@ -351,7 +337,30 @@ async fn main() -> Result<()> {
let stopping = state.clone();
tokio::pin!(server_fut);
+ // Joins, then runs until stopped; returns only if joining fails.
+ let joining = async {
+ bootstrap::bootstrap(&state, &seeds, start)
+ .await
+ .context("Joining swarm")?;
+ node::spawn_ready_workers(&state);
+ info!(
+ swarm_id = ?state.swarm_id().await,
+ ready = state.is_ready().await,
+ "Bootstrap completed"
+ );
+ swarm::state_file::update(&state, true).await;
+ joined.store(true, Ordering::Release);
+ std::future::pending::<Result<()>>().await
+ };
+ tokio::pin!(joining);
+
tokio::select! {
+ failed = joining.as_mut() => {
+ let _ = shutdown_tx.send(());
+ let _ = server_fut.as_mut().await;
+ return failed;
+ }
+
exit_status = state.transport.wait_for_exit() => {
error!(status = ?exit_status, "A transport stopped");
let _ = shutdown_tx.send(());
@@ -364,7 +373,6 @@ async fn main() -> Result<()> {
} else {
info!("Axum HTTP engine shutdown cleanly.");
}
- std::mem::drop(state);
}
_ = stopped(stop.clone()) => {
@@ -374,6 +382,10 @@ async fn main() -> Result<()> {
}
info!("HTTP API server stopped");
+ if !joined.load(Ordering::Acquire) {
+ info!("Stopped while joining the swarm");
+ return Ok(());
+ }
swarm::peer::farewell(&stopping).await;
swarm::state_file::update(&stopping, true).await;
document::file::flush(&stopping).await;