Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3f6b500fc |
+10
-10
@@ -7,7 +7,7 @@ use crate::manifest::Manifest;
|
|||||||
use crate::snapshot;
|
use crate::snapshot;
|
||||||
use crate::sync::{SyncQueue, drain_sync_queue};
|
use crate::sync::{SyncQueue, drain_sync_queue};
|
||||||
use crate::zfs::SystemZfs;
|
use crate::zfs::SystemZfs;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use sysinfo::{ProcessRefreshKind, RefreshKind, System};
|
use sysinfo::{ProcessRefreshKind, RefreshKind, System};
|
||||||
use tokio::time::{interval, Duration};
|
use tokio::time::{interval, Duration};
|
||||||
@@ -36,14 +36,7 @@ pub async fn run(cfg: Config, mut manifest: Manifest) -> Result<()> {
|
|||||||
let hot_dir = cfg.hot.path.clone();
|
let hot_dir = cfg.hot.path.clone();
|
||||||
let hot_max_bytes = cfg.hot.max_gb.saturating_mul(1024 * 1024 * 1024);
|
let hot_max_bytes = cfg.hot.max_gb.saturating_mul(1024 * 1024 * 1024);
|
||||||
let blob_root = cluster_cfg.blob_store_root.clone();
|
let blob_root = cluster_cfg.blob_store_root.clone();
|
||||||
// Fail fast rather than degrade silently: a bind failure here is
|
match ClusterServices::start(
|
||||||
// almost always a boot-time race against DHCP/network-online
|
|
||||||
// (the bind address isn't assigned to the interface yet). The
|
|
||||||
// systemd unit has `Restart=on-failure`; exiting lets it retry
|
|
||||||
// a few seconds later once the network is actually up, instead
|
|
||||||
// of leaving the daemon running indefinitely with no gossip,
|
|
||||||
// RPC, or Prometheus endpoint and no visible failure state.
|
|
||||||
let svc = ClusterServices::start(
|
|
||||||
cluster_cfg,
|
cluster_cfg,
|
||||||
cfg.node.name.clone(),
|
cfg.node.name.clone(),
|
||||||
hot_dir,
|
hot_dir,
|
||||||
@@ -51,7 +44,8 @@ pub async fn run(cfg: Config, mut manifest: Manifest) -> Result<()> {
|
|||||||
blob_root,
|
blob_root,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("starting cluster services")?;
|
{
|
||||||
|
Ok(svc) => {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
rpc_enabled = svc.rpc_enabled(),
|
rpc_enabled = svc.rpc_enabled(),
|
||||||
blob_store_enabled = svc.blob_store_enabled(),
|
blob_store_enabled = svc.blob_store_enabled(),
|
||||||
@@ -60,6 +54,12 @@ pub async fn run(cfg: Config, mut manifest: Manifest) -> Result<()> {
|
|||||||
);
|
);
|
||||||
Some(svc)
|
Some(svc)
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!(error = %e, "cluster services failed to start; continuing without cluster");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
tracing::info!("no [cluster] section in config; running standalone");
|
tracing::info!("no [cluster] section in config; running standalone");
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -91,30 +91,9 @@ impl V2State {
|
|||||||
.join("aggregator-sessions.json");
|
.join("aggregator-sessions.json");
|
||||||
let sessions = SessionStore::load(sessions_path)
|
let sessions = SessionStore::load(sessions_path)
|
||||||
.map_err(|e| anyhow::anyhow!("loading session store: {e}"))?;
|
.map_err(|e| anyhow::anyhow!("loading session store: {e}"))?;
|
||||||
// Bug fix 2026-07-31: the fleet view previously never included
|
|
||||||
// the node actually serving the dashboard — `cluster.peers` is
|
|
||||||
// by definition every *other* node, so hitting a given node's
|
|
||||||
// `/api/v2/fleet` directly silently dropped that node from its
|
|
||||||
// own view (looked like "node X is missing" from the UI, even
|
|
||||||
// though X was perfectly healthy — it just never queried
|
|
||||||
// itself). Fix: synthesize a self `PeerEntry` from our own
|
|
||||||
// gossip bind address and include it in the fan-out list, same
|
|
||||||
// as any other peer. `peer_rpc_addr` derives the RPC port from
|
|
||||||
// `lan_addr`/`tailscale_addr` via the fleet's +1 convention, so
|
|
||||||
// this resolves to the same `bind_rpc_lan`/`bind_rpc_tailscale`
|
|
||||||
// the daemon actually listens on.
|
|
||||||
let self_peer = PeerEntry {
|
|
||||||
name: cfg.node.name.clone(),
|
|
||||||
zone: cluster.zone.clone(),
|
|
||||||
lan_addr: cluster.bind_lan,
|
|
||||||
tailscale_addr: cluster.bind_tailscale,
|
|
||||||
};
|
|
||||||
let mut peers = cluster.peers.clone();
|
|
||||||
peers.push(self_peer);
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
aggregator_name: cfg.node.name.clone(),
|
aggregator_name: cfg.node.name.clone(),
|
||||||
peers,
|
peers: cluster.peers.clone(),
|
||||||
client: std::sync::Arc::new(client),
|
client: std::sync::Arc::new(client),
|
||||||
default_rpc_port_offset: 1,
|
default_rpc_port_offset: 1,
|
||||||
api_token: cfg.api_token.clone(),
|
api_token: cfg.api_token.clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user