gardesk/garwarp / 8060762

Browse files

add status request counters

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
8060762e00ac3772f5daca7c903fdc48e53f8871
Parents
c0fb997
Tree
736ca2f

5 changed files

StatusFile+-
M README.md 1 1
M garwarp-ipc/src/lib.rs 34 3
M garwarp/src/daemon.rs 4 0
M garwarp/src/request.rs 32 0
M garwarpctl/src/main.rs 2 0
README.mdmodified
@@ -18,7 +18,7 @@ Current scaffold includes:
1818
 
1919
 ## Local Commands
2020
 1. Start daemon: `cargo run -p garwarp -- daemon`
21
-2. Check health: `cargo run -p garwarpctl -- status`
21
+2. Check health and request counters: `cargo run -p garwarpctl -- status`
2222
 3. Stop daemon: `cargo run -p garwarpctl -- stop`
2323
 4. Verify D-Bus activation: `./scripts/test-dbus-activation.sh`
2424
 5. Create mock request: `cargo run -p garwarpctl -- begin req-1 :1.2 - x11:0x2a`
garwarp-ipc/src/lib.rsmodified
@@ -198,6 +198,8 @@ pub struct StatusResponse {
198198
     pub protocol_version: u16,
199199
     pub health: HealthStatus,
200200
     pub in_flight_requests: usize,
201
+    pub total_requests: usize,
202
+    pub terminal_requests: usize,
201203
 }
202204
 
203205
 impl StatusResponse {
@@ -207,6 +209,8 @@ impl StatusResponse {
207209
             protocol_version: PROTOCOL_VERSION,
208210
             health: HealthStatus::Healthy,
209211
             in_flight_requests: 0,
212
+            total_requests: 0,
213
+            terminal_requests: 0,
210214
         }
211215
     }
212216
 }
@@ -240,10 +244,12 @@ impl ControlResponse {
240244
     pub fn to_line(&self) -> String {
241245
         match self {
242246
             Self::Status(status) => format!(
243
-                "status protocol={} health={} in_flight={}\n",
247
+                "status protocol={} health={} in_flight={} total={} terminal={}\n",
244248
                 status.protocol_version,
245249
                 status.health.as_str(),
246
-                status.in_flight_requests
250
+                status.in_flight_requests,
251
+                status.total_requests,
252
+                status.terminal_requests
247253
             ),
248254
             Self::AckStopping => "ack stopping\n".to_string(),
249255
             Self::RequestList { ids } => {
@@ -284,6 +290,8 @@ impl ControlResponse {
284290
                 let mut protocol_version = None;
285291
                 let mut health = None;
286292
                 let mut in_flight_requests = None;
293
+                let mut total_requests = None;
294
+                let mut terminal_requests = None;
287295
 
288296
                 for part in parts {
289297
                     let (key, value) = part
@@ -310,6 +318,20 @@ impl ControlResponse {
310318
                                     .map_err(|_| ParseError::InvalidField(part.to_string()))?,
311319
                             );
312320
                         }
321
+                        "total" => {
322
+                            total_requests = Some(
323
+                                value
324
+                                    .parse::<usize>()
325
+                                    .map_err(|_| ParseError::InvalidField(part.to_string()))?,
326
+                            );
327
+                        }
328
+                        "terminal" => {
329
+                            terminal_requests = Some(
330
+                                value
331
+                                    .parse::<usize>()
332
+                                    .map_err(|_| ParseError::InvalidField(part.to_string()))?,
333
+                            );
334
+                        }
313335
                         _ => return Err(ParseError::InvalidField(part.to_string())),
314336
                     }
315337
                 }
@@ -320,6 +342,9 @@ impl ControlResponse {
320342
                     health: health.ok_or(ParseError::MissingField("health"))?,
321343
                     in_flight_requests: in_flight_requests
322344
                         .ok_or(ParseError::MissingField("in_flight"))?,
345
+                    total_requests: total_requests.ok_or(ParseError::MissingField("total"))?,
346
+                    terminal_requests: terminal_requests
347
+                        .ok_or(ParseError::MissingField("terminal"))?,
323348
                 };
324349
                 Ok(Self::Status(status))
325350
             }
@@ -527,6 +552,8 @@ mod tests {
527552
             protocol_version: PROTOCOL_VERSION,
528553
             health: HealthStatus::Healthy,
529554
             in_flight_requests: 7,
555
+            total_requests: 10,
556
+            terminal_requests: 3,
530557
         });
531558
         let line = response.to_line();
532559
         let parsed = ControlResponse::parse_line(&line).expect("response should parse");
@@ -569,11 +596,15 @@ mod tests {
569596
         assert_eq!(response.protocol_version, PROTOCOL_VERSION);
570597
         assert_eq!(response.health, HealthStatus::Healthy);
571598
         assert_eq!(response.in_flight_requests, 0);
599
+        assert_eq!(response.total_requests, 0);
600
+        assert_eq!(response.terminal_requests, 0);
572601
     }
573602
 
574603
     #[test]
575604
     fn malformed_status_is_rejected() {
576
-        let parsed = ControlResponse::parse_line("status protocol=one health=healthy in_flight=0");
605
+        let parsed = ControlResponse::parse_line(
606
+            "status protocol=one health=healthy in_flight=0 total=0 terminal=0",
607
+        );
577608
         assert!(parsed.is_err());
578609
     }
579610
 
garwarp/src/daemon.rsmodified
@@ -117,6 +117,8 @@ fn handle_connection(stream: UnixStream, state: &mut DaemonState) -> io::Result<
117117
             protocol_version: garwarp_ipc::PROTOCOL_VERSION,
118118
             health: state.health,
119119
             in_flight_requests: state.requests.in_flight_count(),
120
+            total_requests: state.requests.total_count(),
121
+            terminal_requests: state.requests.terminal_count(),
120122
         }),
121123
         Some(ControlRequest::Stop) => {
122124
             state.health = HealthStatus::Stopping;
@@ -388,6 +390,8 @@ mod tests {
388390
             ControlResponse::Status(status) => {
389391
                 assert_eq!(status.health, HealthStatus::Healthy);
390392
                 assert_eq!(status.in_flight_requests, 1);
393
+                assert_eq!(status.total_requests, 1);
394
+                assert_eq!(status.terminal_requests, 0);
391395
             }
392396
             _ => panic!("expected status response"),
393397
         }
garwarp/src/request.rsmodified
@@ -264,6 +264,19 @@ impl RequestRegistry {
264264
             .count()
265265
     }
266266
 
267
+    #[must_use]
268
+    pub fn total_count(&self) -> usize {
269
+        self.entries.len()
270
+    }
271
+
272
+    #[must_use]
273
+    pub fn terminal_count(&self) -> usize {
274
+        self.entries
275
+            .values()
276
+            .filter(|entry| entry.state.is_terminal())
277
+            .count()
278
+    }
279
+
267280
     #[must_use]
268281
     pub fn state(&self, id: &str) -> Option<RequestState> {
269282
         self.entries.get(id).map(|entry| entry.state)
@@ -562,6 +575,25 @@ mod tests {
562575
         assert_eq!(registry.state("req-1"), Some(RequestState::Pending));
563576
     }
564577
 
578
+    #[test]
579
+    fn count_helpers_return_expected_values() {
580
+        let now = Instant::now();
581
+        let mut registry = RequestRegistry::new(Duration::from_secs(5));
582
+        registry
583
+            .begin_at("req-1", owner(":1.2"), None, now)
584
+            .expect("request should be created");
585
+        registry
586
+            .begin_at("req-2", owner(":1.3"), None, now)
587
+            .expect("request should be created");
588
+        registry
589
+            .transition_at("req-2", &owner(":1.3"), RequestState::Cancelled, now)
590
+            .expect("request should transition");
591
+
592
+        assert_eq!(registry.total_count(), 2);
593
+        assert_eq!(registry.in_flight_count(), 1);
594
+        assert_eq!(registry.terminal_count(), 1);
595
+    }
596
+
565597
     #[test]
566598
     fn duplicate_cancel_is_idempotent() {
567599
         let now = Instant::now();
garwarpctl/src/main.rsmodified
@@ -173,6 +173,8 @@ fn run(command: Command) -> io::Result<()> {
173173
                     println!("protocol={}", status.protocol_version);
174174
                     println!("health={}", status.health.as_str());
175175
                     println!("in_flight={}", status.in_flight_requests);
176
+                    println!("total={}", status.total_requests);
177
+                    println!("terminal={}", status.terminal_requests);
176178
                     Ok(())
177179
                 }
178180
                 ControlResponse::Error { code, reason } => Err(io::Error::other(format!(