Skip to main content

hydracache_server/
services.rs

1use std::time::Duration;
2
3use serde::Serialize;
4
5/// Background service set tracked by the daemon.
6#[derive(Debug, Clone, Default, PartialEq, Eq)]
7pub struct ServiceSet {
8    running: bool,
9    in_flight: usize,
10}
11
12impl ServiceSet {
13    /// Start background services.
14    pub fn start(&mut self) {
15        self.running = true;
16    }
17
18    /// Stop background services.
19    pub fn stop(&mut self) {
20        self.running = false;
21    }
22
23    /// Track a newly accepted request.
24    pub fn begin_request(&mut self) {
25        self.in_flight = self.in_flight.saturating_add(1);
26    }
27
28    /// Track a completed request.
29    pub fn finish_request(&mut self) {
30        self.in_flight = self.in_flight.saturating_sub(1);
31    }
32
33    /// Return active request count.
34    pub fn in_flight(&self) -> usize {
35        self.in_flight
36    }
37
38    /// Return whether services are running.
39    pub fn is_running(&self) -> bool {
40        self.running
41    }
42}
43
44/// Graceful drain controller.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub struct GracefulShutdown {
47    drain_timeout: Duration,
48}
49
50impl GracefulShutdown {
51    /// Create a drain controller.
52    pub fn new(drain_timeout: Duration) -> Self {
53        Self { drain_timeout }
54    }
55
56    /// Drain in-flight work in a deterministic fast-test model.
57    pub fn drain(&self, services: &mut ServiceSet) -> DrainOutcome {
58        let started_with = services.in_flight();
59        let timed_out = self.drain_timeout.is_zero() && started_with > 0;
60        if !timed_out {
61            while services.in_flight() > 0 {
62                services.finish_request();
63            }
64        }
65        DrainOutcome {
66            started_with,
67            remaining: services.in_flight(),
68            timed_out,
69        }
70    }
71}
72
73/// Result of a graceful drain.
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
75pub struct DrainOutcome {
76    /// Requests observed when drain started.
77    pub started_with: usize,
78    /// Requests still active after the drain window.
79    pub remaining: usize,
80    /// Whether the drain window timed out.
81    pub timed_out: bool,
82}