Skip to content

hmon: add logic monitor#95

Open
arkjedrz wants to merge 2 commits intoeclipse-score:mainfrom
qorix-group:arkjedrz_logic-monitor
Open

hmon: add logic monitor#95
arkjedrz wants to merge 2 commits intoeclipse-score:mainfrom
qorix-group:arkjedrz_logic-monitor

Conversation

@arkjedrz
Copy link
Contributor

@arkjedrz arkjedrz commented Feb 27, 2026

Add logic monitor to HMON.

Resolved #15

@github-actions
Copy link

github-actions bot commented Feb 27, 2026

License Check Results

🚀 The license check job ran with the Bazel command:

bazel run --lockfile_mode=error //:license-check

Status: ⚠️ Needs Review

Click to expand output
[License Check Output]
Extracting Bazel installation...
Starting local Bazel server (8.4.2) and connecting to it...
INFO: Invocation ID: 770b8c1f-8326-4cac-ada9-4a7b2d761675
Computing main repo mapping: 
Computing main repo mapping: 
Computing main repo mapping: 
WARNING: For repository 'score_rust_policies', the root module requires module version score_rust_policies@0.0.3, but got score_rust_policies@0.0.5 in the resolved dependency graph. Please update the version in your MODULE.bazel or set --check_direct_dependencies=off
Loading: 
Loading: 0 packages loaded
Loading: 0 packages loaded
Loading: 0 packages loaded
    currently loading: 
Loading: 0 packages loaded
    currently loading: 
Loading: 0 packages loaded
    currently loading: 
Loading: 0 packages loaded
    currently loading: 
Analyzing: target //:license-check (1 packages loaded, 0 targets configured)
Analyzing: target //:license-check (1 packages loaded, 0 targets configured)

Analyzing: target //:license-check (46 packages loaded, 9 targets configured)

Analyzing: target //:license-check (89 packages loaded, 9 targets configured)

Analyzing: target //:license-check (145 packages loaded, 2642 targets configured)

Analyzing: target //:license-check (153 packages loaded, 6066 targets configured)

Analyzing: target //:license-check (159 packages loaded, 7867 targets configured)

Analyzing: target //:license-check (165 packages loaded, 7901 targets configured)

Analyzing: target //:license-check (165 packages loaded, 7901 targets configured)

Analyzing: target //:license-check (165 packages loaded, 7901 targets configured)

Analyzing: target //:license-check (165 packages loaded, 7901 targets configured)

Analyzing: target //:license-check (169 packages loaded, 9913 targets configured)

INFO: Analyzed target //:license-check (170 packages loaded, 10039 targets configured).
[12 / 16] JavaToolchainCompileClasses external/rules_java+/toolchains/platformclasspath_classes; 0s disk-cache, processwrapper-sandbox ... (2 actions, 1 running)
[15 / 16] [Prepa] Building license.check.license_check.jar ()
INFO: Found 1 target...
Target //:license.check.license_check up-to-date:
  bazel-bin/license.check.license_check
  bazel-bin/license.check.license_check.jar
INFO: Elapsed time: 25.897s, Critical Path: 2.67s
INFO: 16 processes: 12 internal, 3 processwrapper-sandbox, 1 worker.
INFO: Build completed successfully, 16 total actions
INFO: Running command line: bazel-bin/license.check.license_check ./formatted.txt <args omitted>
usage: org.eclipse.dash.licenses.cli.Main [-batch <int>] [-cd <url>]
       [-confidence <int>] [-ef <url>] [-excludeSources <sources>] [-help] [-lic
       <url>] [-project <shortname>] [-repo <url>] [-review] [-summary <file>]
       [-timeout <seconds>] [-token <token>]

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the health monitoring library with new monitor types (heartbeat + logic) and refactors the worker/supervisor client plumbing so the worker can evaluate multiple monitor kinds and report typed evaluation errors across Rust + C++/FFI.

Changes:

  • Add new HeartbeatMonitor (state + evaluator + FFI + C++ wrapper) and LogicMonitor (state-transition validator).
  • Refactor monitor evaluation to pass an HMON starting Instant and to report typed MonitorEvaluationError variants (deadline/heartbeat/logic).
  • Move supervisor API client implementations into a feature-gated supervisor_api_client/ module and adjust build config defaults/features.

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/health_monitoring_lib/rust/worker.rs Updates monitoring loop to pass a shared starting Instant and log typed monitor errors; removes in-file supervisor client impls.
src/health_monitoring_lib/rust/tag.rs Adds StateTag newtype for logic monitor states; updates tag tests.
src/health_monitoring_lib/rust/supervisor_api_client/stub_supervisor_api_client.rs Adds stub supervisor client implementation behind feature gate.
src/health_monitoring_lib/rust/supervisor_api_client/score_supervisor_api_client.rs Adds SCORE supervisor client implementation (monitor_rs-backed).
src/health_monitoring_lib/rust/supervisor_api_client/mod.rs Introduces SupervisorAPIClient trait and feature-gated implementations.
src/health_monitoring_lib/rust/logic/mod.rs Adds logic module exports.
src/health_monitoring_lib/rust/logic/logic_monitor.rs Implements logic monitor state machine + evaluator + tests.
src/health_monitoring_lib/rust/lib.rs Integrates deadline/heartbeat/logic monitors into HealthMonitorBuilder + HealthMonitor; changes build/start to return Result.
src/health_monitoring_lib/rust/heartbeat/mod.rs Adds heartbeat module wiring and FFI submodule.
src/health_monitoring_lib/rust/heartbeat/heartbeat_state.rs Adds compact atomic heartbeat state representation (+ loom-aware atomics).
src/health_monitoring_lib/rust/heartbeat/heartbeat_monitor.rs Adds heartbeat monitor implementation + builder validation + tests.
src/health_monitoring_lib/rust/heartbeat/ffi.rs Adds FFI for heartbeat monitor builder/monitor and tests.
src/health_monitoring_lib/rust/ffi.rs Extends core FFI to build/start using Result, adds heartbeat builder/get FFI, and maps HealthMonitorError to FFICode.
src/health_monitoring_lib/rust/deadline/mod.rs Re-exports DeadlineEvaluationError for typed evaluation errors.
src/health_monitoring_lib/rust/deadline/deadline_monitor.rs Refactors deadline monitor to use typed DeadlineEvaluationError and updated evaluator signature.
src/health_monitoring_lib/rust/common.rs Introduces HasEvalHandle, typed MonitorEvaluationError, shared evaluation signature, and time conversion helpers.
src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp Extends C++ test to build/get/use heartbeat monitor.
src/health_monitoring_lib/cpp/include/score/hm/heartbeat/heartbeat_monitor.h Adds C++ API surface for heartbeat monitor + builder.
src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h Adds heartbeat monitor APIs to C++ HealthMonitor(Builder).
src/health_monitoring_lib/cpp/heartbeat_monitor.cpp Implements C++ heartbeat monitor wrapper calling Rust FFI.
src/health_monitoring_lib/cpp/health_monitor.cpp Wires heartbeat builder/get calls through Rust FFI.
src/health_monitoring_lib/Cargo.toml Adds features (default stub; optional score uses monitor_rs) and loom dependency config.
src/health_monitoring_lib/BUILD Adds heartbeat C++ sources/headers and adjusts crate feature flags for Bazel targets.
examples/rust_supervised_app/src/main.rs Updates example to handle build()/start() returning Result.
Cargo.toml Sets workspace default-members and adds cfg(loom) lint configuration.
Cargo.lock Adds new dependency entries (loom + transitive deps).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

match value {
value if value == LogicEvaluationError::InvalidState as u8 => LogicEvaluationError::InvalidState,
value if value == LogicEvaluationError::InvalidTransition as u8 => LogicEvaluationError::InvalidTransition,
_ => panic!("Invalid underlying value of logic evaluation error."),
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

impl From<u8> for LogicEvaluationError panics on unknown values. Since this conversion is used when interpreting AtomicU8 state during evaluate, an unexpected value would crash the monitoring thread/process instead of reporting an error. Please make this conversion non-panicking (e.g., map unknown values to InvalidState or return Option/Result) and handle that path in evaluate.

Suggested change
_ => panic!("Invalid underlying value of logic evaluation error."),
_ => LogicEvaluationError::InvalidState,

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

The created documentation from the pull request is available at: docu-html

@arkjedrz arkjedrz force-pushed the arkjedrz_logic-monitor branch from 38a2bdf to 07352fd Compare March 2, 2026 07:34
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 2, 2026 07:34 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 2, 2026 07:34 — with GitHub Actions Inactive
@arkjedrz arkjedrz force-pushed the arkjedrz_logic-monitor branch from 07352fd to f96e585 Compare March 3, 2026 13:07
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 3, 2026 13:07 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 3, 2026 13:07 — with GitHub Actions Inactive
@arkjedrz arkjedrz force-pushed the arkjedrz_logic-monitor branch from f96e585 to 4ab21c9 Compare March 4, 2026 14:50
@arkjedrz arkjedrz requested a deployment to workflow-approval March 4, 2026 14:50 — with GitHub Actions Waiting
@arkjedrz arkjedrz requested a deployment to workflow-approval March 4, 2026 14:50 — with GitHub Actions Waiting
@arkjedrz arkjedrz force-pushed the arkjedrz_logic-monitor branch from 4ab21c9 to 743411c Compare March 5, 2026 10:32
@arkjedrz arkjedrz requested a deployment to workflow-approval March 5, 2026 10:32 — with GitHub Actions Waiting
@arkjedrz arkjedrz requested a deployment to workflow-approval March 5, 2026 10:32 — with GitHub Actions Waiting
@arkjedrz arkjedrz marked this pull request as ready for review March 5, 2026 10:45
@arkjedrz arkjedrz requested a review from Copilot March 5, 2026 10:46
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link
Contributor

@pawelrutkaq pawelrutkaq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stopped as my comment will probably simplify more code

@arkjedrz arkjedrz force-pushed the arkjedrz_logic-monitor branch from 743411c to 4686fb0 Compare March 5, 2026 13:58
@arkjedrz arkjedrz requested a deployment to workflow-approval March 5, 2026 13:58 — with GitHub Actions Waiting
@arkjedrz arkjedrz requested a deployment to workflow-approval March 5, 2026 13:58 — with GitHub Actions Waiting

protected:
std::optional<internal::FFIHandle> __drop_by_rust_impl()
std::optional<internal::FFIHandle> _drop_by_rust_impl()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_drop_by_rust_impl -> drop_by_rust_impl

Compilers like GCC, Clang, and MSVC often use leading underscores for internal macros or system-level functions. If a future update to your compiler introduces a macro or an internal header named _drop_by_rust_impl, your code will fail to compile—or worse, behave unpredictably—and it will be considered your fault, not the compiler’s, because you used a reserved naming pattern.

Copy link
Contributor

@paulquiring paulquiring Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__ and _ is just considered not a good style. They are reserved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That one's fine. It was previously double underscore, and that's actually an issue.
https://devblogs.microsoft.com/oldnewthing/20230109-00/?p=107685

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes one underscore flowed by a lower letter is not and issue. One underscore followed by a capital letter is also reserved. From the link you shared:

grafik

It is best practice to use the namespace detail or internal to indicate to user to not use it directly.

@paulquiring
Copy link
Contributor

The rust part looks like it supports monitoring from multiple threads. I could not find any hint how to set this up correctly form the cpp side.

@arkjedrz arkjedrz force-pushed the arkjedrz_logic-monitor branch from 4686fb0 to 6247d38 Compare March 6, 2026 12:58
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 6, 2026 12:58 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 6, 2026 12:58 — with GitHub Actions Inactive
arkjedrz added 2 commits March 6, 2026 14:25
Add logic monitor to HMON.
- Add const constructor to `StateTag`.
- Atomic `LogicState` containing current state index and monitor status.
- Updated logic monitor API.
- Reworked internal of logic monitor.
@arkjedrz arkjedrz force-pushed the arkjedrz_logic-monitor branch from 6247d38 to 48bc6f2 Compare March 6, 2026 13:28
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 6, 2026 13:28 — with GitHub Actions Inactive
@arkjedrz arkjedrz deployed to workflow-approval March 6, 2026 13:28 — with GitHub Actions Active
#[cfg(not(loom))]
use core::sync::atomic::{AtomicU64, Ordering};
#[cfg(loom)]
use loom::sync::atomic::{AtomicU64, Ordering};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ifdef shall be hidden in some common place, maybe even baselibs

/// Monitor status.
/// - zero if healthy.
/// - `LogicEvaluationError` if not.
pub fn monitor_status(&self) -> u8 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't that be bool returned?

InvalidState = OK_STATE + 1,
/// Transition is invalid.
InvalidTransition,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this is what you store as error in the shared state, we shall make this type as input into snapshot and not raw u8

impl From<u8> for LogicEvaluationError {
fn from(value: u8) -> Self {
match value {
value if value == LogicEvaluationError::InvalidState as u8 => LogicEvaluationError::InvalidState,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we cannot match for LogicEvaluationError::InvalidState, LogicEvaluationError::InvalidTransition and for _ without ifs ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw We shall implement TryFrom if this can fail. as From is not failable

current_state_node.tag, target_state
);
let error = LogicEvaluationError::InvalidTransition;
let _ = self.logic_state.update(|mut current_state| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the handle is only reading the values, you can simply use store or swap, no need to use update

}

// Find index of target state, then change current state.
let target_state_index = self.find_index_by_tag(target_state)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Further optimization would be to keep with the target states their indexes so you don't need to do any lookups.


// Find index of target state, then change current state.
let target_state_index = self.find_index_by_tag(target_state)?;
let _ = self.logic_state.update(|mut current_state| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no update needed as above


// Disallow operation in erroneous state.
if snapshot.monitor_status() != OK_STATE {
warn!("Current logic monitor state cannot be determined");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually it can and its error. maybe log is not needed

// Disallow operation in erroneous state.
if snapshot.monitor_status() != OK_STATE {
warn!("Current logic monitor state cannot be determined");
return Err(LogicEvaluationError::InvalidState);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shdnt status be properly converted here instead hardocoded?


/// Perform transition to a new state.
/// On success, current state is returned.
pub fn transition(&self, state: StateTag) -> Result<StateTag, LogicEvaluationError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LogicMonitor shall be restricted to a single thread only. Currently, I think it's both Send and Sync. So either we remove Sync or make the public api mutable just to remove cross-thread usage without proper locking. I think other Monitors have same issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HmLib] Rust Logical Monitor API

4 participants