feat: Health command — version, pid, started_at (proto + daemon)
This commit is contained in:
@@ -122,6 +122,7 @@ pub enum Cmd {
|
|||||||
limit: Option<u32>,
|
limit: Option<u32>,
|
||||||
},
|
},
|
||||||
MarkRead { target: MarkReadTarget },
|
MarkRead { target: MarkReadTarget },
|
||||||
|
Health,
|
||||||
Status,
|
Status,
|
||||||
Shutdown,
|
Shutdown,
|
||||||
}
|
}
|
||||||
@@ -321,6 +322,15 @@ mod tests {
|
|||||||
assert_eq!(back, evt);
|
assert_eq!(back, evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn health_cmd_round_trips() {
|
||||||
|
let env = Envelope::Req { id: 1, cmd: Cmd::Health };
|
||||||
|
let j = serde_json::to_string(&env).unwrap();
|
||||||
|
assert!(j.contains(r#""cmd":"health""#));
|
||||||
|
let back: Envelope = serde_json::from_str(&j).unwrap();
|
||||||
|
assert_eq!(back, env);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn event_log_cmd_no_limit_round_trips() {
|
fn event_log_cmd_no_limit_round_trips() {
|
||||||
let env = Envelope::Req { id: 9, cmd: Cmd::EventLog { limit: None } };
|
let env = Envelope::Req { id: 9, cmd: Cmd::EventLog { limit: None } };
|
||||||
|
|||||||
@@ -62,9 +62,11 @@ pub async fn serve(socket: &Path, store: Arc<dyn StateStore>, event_store: Arc<d
|
|||||||
let initial = store.load().unwrap_or_default();
|
let initial = store.load().unwrap_or_default();
|
||||||
let event_persister = event_store::spawn(event_store.clone(), Duration::from_millis(500));
|
let event_persister = event_store::spawn(event_store.clone(), Duration::from_millis(500));
|
||||||
let event_initial = event_store.load().unwrap_or_default();
|
let event_initial = event_store.load().unwrap_or_default();
|
||||||
|
let started_at_ms = now_millis();
|
||||||
let shutdown = tokio::spawn(router(
|
let shutdown = tokio::spawn(router(
|
||||||
router_rx, router_tx.clone(), exit_tx, state_tx,
|
router_rx, router_tx.clone(), exit_tx, state_tx,
|
||||||
persister, initial, event_persister, event_initial,
|
persister, initial, event_persister, event_initial,
|
||||||
|
started_at_ms,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut next_client: ClientId = 0;
|
let mut next_client: ClientId = 0;
|
||||||
@@ -125,6 +127,7 @@ async fn router(
|
|||||||
initial: crate::state_store::PersistState,
|
initial: crate::state_store::PersistState,
|
||||||
event_persister: EventPersister,
|
event_persister: EventPersister,
|
||||||
event_initial: crate::event_log::EventLogState,
|
event_initial: crate::event_log::EventLogState,
|
||||||
|
started_at_ms: u64,
|
||||||
) {
|
) {
|
||||||
let mut reg = Registry::new();
|
let mut reg = Registry::new();
|
||||||
reg.restore(initial);
|
reg.restore(initial);
|
||||||
@@ -174,7 +177,7 @@ async fn router(
|
|||||||
ServerMsg::Request { id, cmd, client, out } => {
|
ServerMsg::Request { id, cmd, client, out } => {
|
||||||
handle_request(id, cmd, client, out, &mut reg, &mut subs, &clients,
|
handle_request(id, cmd, client, out, &mut reg, &mut subs, &clients,
|
||||||
&router_tx, &exit_tx, &state_tx, &persister,
|
&router_tx, &exit_tx, &state_tx, &persister,
|
||||||
&mut event_log, &event_persister).await;
|
&mut event_log, &event_persister, started_at_ms).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,6 +275,7 @@ async fn handle_request(
|
|||||||
persister: &Persister,
|
persister: &Persister,
|
||||||
event_log: &mut EventLog,
|
event_log: &mut EventLog,
|
||||||
event_persister: &EventPersister,
|
event_persister: &EventPersister,
|
||||||
|
started_at_ms: u64,
|
||||||
) {
|
) {
|
||||||
use spacesh_proto::message::SplitDir;
|
use spacesh_proto::message::SplitDir;
|
||||||
use spacesh_proto::layout::{LayoutNode, Orient};
|
use spacesh_proto::layout::{LayoutNode, Orient};
|
||||||
@@ -590,6 +594,14 @@ async fn handle_request(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cmd::Health => {
|
||||||
|
let _ = out.send(ok(id, serde_json::json!({
|
||||||
|
"version": env!("CARGO_PKG_VERSION"),
|
||||||
|
"pid": std::process::id(),
|
||||||
|
"started_at_ms": started_at_ms,
|
||||||
|
}))).await;
|
||||||
|
}
|
||||||
|
|
||||||
Cmd::Status => {
|
Cmd::Status => {
|
||||||
let (groups, workspaces) = reg.status();
|
let (groups, workspaces) = reg.status();
|
||||||
let _ = out.send(ok(id, serde_json::json!({ "groups": groups, "workspaces": workspaces }))).await;
|
let _ = out.send(ok(id, serde_json::json!({ "groups": groups, "workspaces": workspaces }))).await;
|
||||||
@@ -1300,4 +1312,27 @@ mod tests {
|
|||||||
let log = req(&mut s, 6, Cmd::EventLog { limit: None }).await;
|
let log = req(&mut s, 6, Cmd::EventLog { limit: None }).await;
|
||||||
assert_eq!(res_data(&log)["unread"].as_u64().unwrap(), 0);
|
assert_eq!(res_data(&log)["unread"].as_u64().unwrap(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn health_reports_version_pid_started() {
|
||||||
|
let _serial = crate::test_support::serial();
|
||||||
|
let dir = tempdir_path();
|
||||||
|
let sock = dir.join("sock");
|
||||||
|
let store: std::sync::Arc<dyn crate::state_store::StateStore> =
|
||||||
|
std::sync::Arc::new(crate::state_store::JsonStateStore::new(dir.join("state.json")));
|
||||||
|
let event_store = make_event_store(&dir);
|
||||||
|
let sock_for_task = sock.clone();
|
||||||
|
let store2 = store.clone();
|
||||||
|
tokio::spawn(async move { let _ = serve(&sock_for_task, store2, event_store).await; });
|
||||||
|
wait_for_socket(&sock).await;
|
||||||
|
let mut s = UnixStream::connect(&sock).await.unwrap();
|
||||||
|
|
||||||
|
let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as u64;
|
||||||
|
let r = req(&mut s, 1, Cmd::Health).await;
|
||||||
|
let d = res_data(&r);
|
||||||
|
assert!(!d["version"].as_str().unwrap().is_empty());
|
||||||
|
assert!(d["pid"].as_u64().unwrap() > 0);
|
||||||
|
let started = d["started_at_ms"].as_u64().unwrap();
|
||||||
|
assert!(started > 0 && started >= now.saturating_sub(5000) && started <= now + 1000, "started_at_ms plausible: {started} vs now {now}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user