Skip to content

Commit 94920a7

Browse files
committed
hmon: approach to monitors rework
- Restore some parts. - Separate errors into groups.
1 parent ba0a564 commit 94920a7

6 files changed

Lines changed: 198 additions & 112 deletions

File tree

src/health_monitoring_lib/rust/common.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
// SPDX-License-Identifier: Apache-2.0
1212
// *******************************************************************************
1313

14+
use crate::deadline::DeadlineEvaluationError;
15+
use crate::log::ScoreDebug;
16+
use crate::tag::MonitorTag;
1417
use core::hash::Hash;
1518
use core::time::Duration;
19+
use std::sync::Arc;
1620

1721
/// Range of accepted time.
1822
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -27,3 +31,51 @@ impl TimeRange {
2731
Self { min, max }
2832
}
2933
}
34+
35+
/// The monitor has an evaluation handle available.
36+
pub(crate) trait HasEvalHandle {
37+
/// Get an evaluation handle for this monitor.
38+
///
39+
/// # NOTE
40+
///
41+
/// This method is intended to be called from a background thread periodically.
42+
fn get_eval_handle(&self) -> MonitorEvalHandle;
43+
}
44+
45+
/// Errors that can occur during monitor evaluation.
46+
/// Contains failing monitor type.
47+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, ScoreDebug)]
48+
#[allow(dead_code)]
49+
pub(crate) enum MonitorEvaluationError {
50+
Deadline(DeadlineEvaluationError),
51+
Heartbeat,
52+
Logic,
53+
}
54+
55+
impl From<DeadlineEvaluationError> for MonitorEvaluationError {
56+
fn from(value: DeadlineEvaluationError) -> Self {
57+
MonitorEvaluationError::Deadline(value)
58+
}
59+
}
60+
61+
/// Trait for evaluating monitors and reporting errors to be used by HealthMonitor.
62+
pub(crate) trait MonitorEvaluator {
63+
fn evaluate(&self, on_error: &mut dyn FnMut(&MonitorTag, MonitorEvaluationError));
64+
}
65+
66+
/// Handle to a monitor evaluator, allowing for dynamic dispatch.
67+
pub(crate) struct MonitorEvalHandle {
68+
inner: Arc<dyn MonitorEvaluator + Send + Sync>,
69+
}
70+
71+
impl MonitorEvalHandle {
72+
pub(crate) fn new<T: MonitorEvaluator + Send + Sync + 'static>(inner: Arc<T>) -> Self {
73+
Self { inner }
74+
}
75+
}
76+
77+
impl MonitorEvaluator for MonitorEvalHandle {
78+
fn evaluate(&self, on_error: &mut dyn FnMut(&MonitorTag, MonitorEvaluationError)) {
79+
self.inner.evaluate(on_error)
80+
}
81+
}

src/health_monitoring_lib/rust/deadline/deadline_monitor.rs

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
// SPDX-License-Identifier: Apache-2.0
1212
// *******************************************************************************
13+
use crate::common::{HasEvalHandle, MonitorEvalHandle, MonitorEvaluationError, MonitorEvaluator};
1314
use crate::deadline::common::{DeadlineTemplate, StateIndex};
1415
use crate::deadline::deadline_state::{DeadlineState, DeadlineStateSnapshot};
1516
use crate::log::{error, warn, ScoreDebug};
@@ -23,7 +24,7 @@ use std::time::Instant;
2324

2425
/// Deadline evaluation errors.
2526
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, ScoreDebug)]
26-
pub(crate) enum DeadlineEvalError {
27+
pub(crate) enum DeadlineEvaluationError {
2728
/// Finished too early.
2829
TooEarly,
2930
/// Finished too late.
@@ -69,12 +70,9 @@ impl DeadlineMonitorBuilder {
6970
}
7071

7172
/// Builds the DeadlineMonitor with the configured deadlines.
72-
pub(crate) fn build(
73-
self,
74-
monitor_tag: MonitorTag,
75-
_allocator: &ProtectedMemoryAllocator,
76-
) -> Arc<DeadlineMonitorInner> {
77-
Arc::new(DeadlineMonitorInner::new(monitor_tag, self.deadlines))
73+
pub(crate) fn build(self, monitor_tag: MonitorTag, _allocator: &ProtectedMemoryAllocator) -> DeadlineMonitor {
74+
let inner = Arc::new(DeadlineMonitorInner::new(monitor_tag, self.deadlines));
75+
DeadlineMonitor::new(inner)
7876
}
7977

8078
// Used by FFI and config parsing code which prefer not to move builder instance
@@ -90,7 +88,7 @@ pub struct DeadlineMonitor {
9088

9189
impl DeadlineMonitor {
9290
/// Create a new [`DeadlineMonitor`] instance.
93-
pub(crate) fn new(inner: Arc<DeadlineMonitorInner>) -> Self {
91+
fn new(inner: Arc<DeadlineMonitorInner>) -> Self {
9492
Self { inner }
9593
}
9694

@@ -104,6 +102,12 @@ impl DeadlineMonitor {
104102
}
105103
}
106104

105+
impl HasEvalHandle for DeadlineMonitor {
106+
fn get_eval_handle(&self) -> MonitorEvalHandle {
107+
MonitorEvalHandle::new(Arc::clone(&self.inner))
108+
}
109+
}
110+
107111
/// Represents a deadline that can be started and stopped.
108112
pub struct Deadline {
109113
range: TimeRange,
@@ -191,7 +195,7 @@ impl Deadline {
191195

192196
let expected = current.timestamp_ms();
193197
if expected < now {
194-
possible_err = (Some(DeadlineEvalError::TooLate), now - expected);
198+
possible_err = (Some(DeadlineEvaluationError::TooLate), now - expected);
195199
return None; // Deadline missed, let state as is for BG thread to report
196200
}
197201

@@ -202,18 +206,18 @@ impl Deadline {
202206
// Finished too early, leave it for reporting by BG thread
203207

204208
current.set_underrun();
205-
possible_err = (Some(DeadlineEvalError::TooEarly), earliest_time - now);
209+
possible_err = (Some(DeadlineEvaluationError::TooEarly), earliest_time - now);
206210
return Some(current);
207211
}
208212

209213
Some(DeadlineStateSnapshot::default()) // Reset to stopped state as all fine
210214
});
211215

212216
match possible_err {
213-
(Some(DeadlineEvalError::TooEarly), val) => {
217+
(Some(DeadlineEvaluationError::TooEarly), val) => {
214218
error!("Deadline {:?} stopped too early by {} ms", self.deadline_tag, val);
215219
},
216-
(Some(DeadlineEvalError::TooLate), val) => {
220+
(Some(DeadlineEvaluationError::TooLate), val) => {
217221
error!("Deadline {:?} stopped too late by {} ms", self.deadline_tag, val);
218222
},
219223
(None, _) => {},
@@ -239,7 +243,7 @@ impl Drop for Deadline {
239243
}
240244
}
241245

242-
pub(crate) struct DeadlineMonitorInner {
246+
struct DeadlineMonitorInner {
243247
/// Tag of this monitor.
244248
monitor_tag: MonitorTag,
245249

@@ -255,6 +259,39 @@ pub(crate) struct DeadlineMonitorInner {
255259
active_deadlines: Arc<[(DeadlineTag, DeadlineState)]>,
256260
}
257261

262+
impl MonitorEvaluator for DeadlineMonitorInner {
263+
fn evaluate(&self, on_error: &mut dyn FnMut(&MonitorTag, MonitorEvaluationError)) {
264+
for (deadline_tag, deadline) in self.active_deadlines.iter() {
265+
let snapshot = deadline.snapshot();
266+
if snapshot.is_underrun() {
267+
// Deadline finished too early, report
268+
warn!("Deadline ({:?}) finished too early!", deadline_tag);
269+
270+
// Here we would normally report the underrun to the monitoring system
271+
on_error(&self.monitor_tag, DeadlineEvaluationError::TooEarly.into());
272+
} else if snapshot.is_running() {
273+
debug_assert!(
274+
snapshot.is_stopped(),
275+
"Deadline snapshot cannot be both running and stopped"
276+
);
277+
278+
let now = self.now();
279+
let expected = snapshot.timestamp_ms();
280+
if now > expected {
281+
// Deadline missed, report
282+
warn!(
283+
"Deadline ({:?}) missed! Expected: {}, now: {}",
284+
deadline_tag, expected, now
285+
);
286+
287+
// Here we would normally report the missed deadline to the monitoring system
288+
on_error(&self.monitor_tag, DeadlineEvaluationError::TooLate.into());
289+
}
290+
}
291+
}
292+
}
293+
}
294+
258295
impl DeadlineMonitorInner {
259296
fn new(monitor_tag: MonitorTag, deadlines: HashMap<DeadlineTag, TimeRange>) -> Self {
260297
let mut active_deadlines = vec![];
@@ -307,37 +344,6 @@ impl DeadlineMonitorInner {
307344
// We still have a room up to 60bits timestamp if needed in future
308345
u32::try_from(duration.as_millis()).expect("Monitor running for too long")
309346
}
310-
311-
pub(crate) fn evaluate(&self, on_error: &mut dyn FnMut(&MonitorTag, DeadlineEvalError)) {
312-
for (deadline_tag, deadline) in self.active_deadlines.iter() {
313-
let snapshot = deadline.snapshot();
314-
if snapshot.is_underrun() {
315-
// Deadline finished too early, report
316-
warn!("Deadline ({:?}) finished too early!", deadline_tag);
317-
318-
// Here we would normally report the underrun to the monitoring system
319-
on_error(&self.monitor_tag, DeadlineEvalError::TooEarly);
320-
} else if snapshot.is_running() {
321-
debug_assert!(
322-
snapshot.is_stopped(),
323-
"Deadline snapshot cannot be both running and stopped"
324-
);
325-
326-
let now = self.now();
327-
let expected = snapshot.timestamp_ms();
328-
if now > expected {
329-
// Deadline missed, report
330-
warn!(
331-
"Deadline ({:?}) missed! Expected: {}, now: {}",
332-
deadline_tag, expected, now
333-
);
334-
335-
// Here we would normally report the missed deadline to the monitoring system
336-
on_error(&self.monitor_tag, DeadlineEvalError::TooLate);
337-
}
338-
}
339-
}
340-
}
341347
}
342348

343349
#[score_testing_macros::test_mod_with_log]
@@ -348,7 +354,7 @@ mod tests {
348354
fn create_monitor_with_deadlines() -> DeadlineMonitor {
349355
let allocator = ProtectedMemoryAllocator {};
350356
let monitor_tag = MonitorTag::from("deadline_monitor");
351-
let inner = DeadlineMonitorBuilder::new()
357+
DeadlineMonitorBuilder::new()
352358
.add_deadline(
353359
DeadlineTag::from("deadline_long"),
354360
TimeRange::new(core::time::Duration::from_secs(1), core::time::Duration::from_secs(50)),
@@ -360,14 +366,13 @@ mod tests {
360366
core::time::Duration::from_millis(50),
361367
),
362368
)
363-
.build(monitor_tag, &allocator);
364-
DeadlineMonitor::new(inner)
369+
.build(monitor_tag, &allocator)
365370
}
366371

367372
fn create_monitor_with_multiple_running_deadlines() -> DeadlineMonitor {
368373
let allocator = ProtectedMemoryAllocator {};
369374
let monitor_tag = MonitorTag::from("deadline_monitor");
370-
let inner = DeadlineMonitorBuilder::new()
375+
DeadlineMonitorBuilder::new()
371376
.add_deadline(
372377
DeadlineTag::from("slow"),
373378
TimeRange::new(core::time::Duration::from_secs(0), core::time::Duration::from_secs(50)),
@@ -393,8 +398,7 @@ mod tests {
393398
core::time::Duration::from_millis(10),
394399
),
395400
)
396-
.build(monitor_tag, &allocator);
397-
DeadlineMonitor::new(inner)
401+
.build(monitor_tag, &allocator)
398402
}
399403

400404
#[test]
@@ -433,7 +437,7 @@ mod tests {
433437
monitor.inner.evaluate(&mut |monitor_tag, deadline_failure| {
434438
assert_eq!(
435439
deadline_failure,
436-
DeadlineEvalError::TooEarly,
440+
DeadlineEvaluationError::TooEarly.into(),
437441
"Deadline {:?} should not have failed({:?})",
438442
monitor_tag,
439443
deadline_failure
@@ -451,7 +455,7 @@ mod tests {
451455
monitor.inner.evaluate(&mut |monitor_tag, deadline_failure| {
452456
assert_eq!(
453457
deadline_failure,
454-
DeadlineEvalError::TooEarly,
458+
DeadlineEvaluationError::TooEarly.into(),
455459
"Deadline {:?} should not have failed({:?})",
456460
monitor_tag,
457461
deadline_failure
@@ -477,7 +481,7 @@ mod tests {
477481
monitor.inner.evaluate(&mut |monitor_tag, deadline_failure| {
478482
assert_eq!(
479483
deadline_failure,
480-
DeadlineEvalError::TooEarly,
484+
DeadlineEvaluationError::TooEarly.into(),
481485
"Deadline {:?} should not have failed ({:?})",
482486
monitor_tag,
483487
deadline_failure
@@ -496,7 +500,7 @@ mod tests {
496500
monitor.inner.evaluate(&mut |monitor_tag, deadline_failure| {
497501
assert_eq!(
498502
deadline_failure,
499-
DeadlineEvalError::TooLate,
503+
DeadlineEvaluationError::TooLate.into(),
500504
"Deadline {:?} should not have failed({:?})",
501505
monitor_tag,
502506
deadline_failure
@@ -525,7 +529,7 @@ mod tests {
525529
cnt += 1;
526530
assert_eq!(
527531
deadline_failure,
528-
DeadlineEvalError::TooLate,
532+
DeadlineEvaluationError::TooLate.into(),
529533
"Deadline {:?} should not have failed({:?})",
530534
monitor_tag,
531535
deadline_failure

src/health_monitoring_lib/rust/deadline/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod common;
1515
mod deadline_monitor;
1616
mod deadline_state;
1717

18-
pub(crate) use deadline_monitor::DeadlineMonitorInner;
18+
pub(crate) use deadline_monitor::DeadlineEvaluationError;
1919
pub use deadline_monitor::{
2020
DeadlineError, DeadlineHandle, DeadlineMonitor, DeadlineMonitorBuilder, DeadlineMonitorError,
2121
};

src/health_monitoring_lib/rust/ffi.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,12 @@ pub extern "C" fn health_monitor_start(health_monitor_handle: FFIHandle) -> FFIC
211211
return FFICode::WrongState;
212212
}
213213

214-
let deadline_monitors = match health_monitor.collect_deadline_monitors_internal() {
214+
let monitors = match health_monitor.collect_monitors_internal() {
215215
Ok(m) => m,
216216
Err(_) => return FFICode::WrongState,
217217
};
218218

219-
health_monitor.start_internal(deadline_monitors);
219+
health_monitor.start_internal(monitors);
220220

221221
FFICode::Success
222222
}

0 commit comments

Comments
 (0)