Skip to content

hmon: add C++ interface to heartbeat monitor#72

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

hmon: add C++ interface to heartbeat monitor#72
arkjedrz wants to merge 2 commits intoeclipse-score:mainfrom
qorix-group:arkjedrz_heartbeat-monitor-cpp

Conversation

@arkjedrz
Copy link
Contributor

Add C++ interface to heartbeat monitor.

Resolves #69

@arkjedrz arkjedrz temporarily deployed to workflow-approval February 11, 2026 11:00 — with GitHub Actions Inactive
@github-actions
Copy link

github-actions bot commented Feb 11, 2026

License Check Results

🚀 The license check job ran with the Bazel command:

bazel run //: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: 4b2aa04f-7cc2-4e1f-8f82-2f912b8e12d4
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
Computing main repo mapping: 
Loading: 
Loading: 0 packages loaded
Loading: 0 packages loaded
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 (43 packages loaded, 9 targets configured)

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

Analyzing: target //:license-check (135 packages loaded, 2450 targets configured)

Analyzing: target //:license-check (148 packages loaded, 5739 targets configured)

Analyzing: target //:license-check (149 packages loaded, 5939 targets configured)

Analyzing: target //:license-check (158 packages loaded, 7792 targets configured)

Analyzing: target //:license-check (160 packages loaded, 7817 targets configured)

Analyzing: target //:license-check (160 packages loaded, 7817 targets configured)

Analyzing: target //:license-check (160 packages loaded, 7817 targets configured)

Analyzing: target //:license-check (162 packages loaded, 8239 targets configured)

Analyzing: target //:license-check (164 packages loaded, 9829 targets configured)

INFO: Analyzed target //:license-check (165 packages loaded, 9955 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.128s, Critical Path: 2.88s
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>]

@github-actions
Copy link

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

@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from 04a90a3 to 93f7fc7 Compare February 11, 2026 12:14
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from 93f7fc7 to b3753a6 Compare February 13, 2026 14:48
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 13, 2026 14:49 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 13, 2026 14:49 — with GitHub Actions Inactive
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from b3753a6 to 89ad2f1 Compare February 17, 2026 12:13
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 17, 2026 12:13 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 17, 2026 12:13 — with GitHub Actions Inactive
@arkjedrz arkjedrz self-assigned this Feb 17, 2026
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 17, 2026 14:37 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 17, 2026 14:37 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 17, 2026 15:06 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 17, 2026 15:06 — with GitHub Actions Inactive
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from 578964b to 8c150e1 Compare February 25, 2026 13:56
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 25, 2026 13:56 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 25, 2026 13:56 — with GitHub Actions Inactive
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from 8c150e1 to 0104ab2 Compare February 26, 2026 11:42
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 26, 2026 11:43 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 26, 2026 11:43 — with GitHub Actions Inactive
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from 0104ab2 to c6e4454 Compare February 26, 2026 12:43
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from c6e4454 to 602b860 Compare February 26, 2026 13:57
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 26, 2026 13:57 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval February 26, 2026 13:57 — with GitHub Actions Inactive
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from 602b860 to eff29f5 Compare March 3, 2026 10:28
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 3, 2026 10:28 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 3, 2026 10:28 — with GitHub Actions Inactive
@arkjedrz arkjedrz requested review from Copilot and pawelrutkaq March 3, 2026 10:28
@arkjedrz arkjedrz marked this pull request as ready for review March 3, 2026 10:28
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from eff29f5 to 9d1ba1c Compare March 3, 2026 10:34
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 adds a new Heartbeat monitor to the health monitoring library and exposes it through the existing C++ API surface (via Rust FFI), integrating it into the HealthMonitor build/start workflow.

Changes:

  • Introduces a Rust HeartbeatMonitor (state, evaluation logic, builder) plus FFI exports for C++.
  • Extends HealthMonitorBuilder / HealthMonitor to store, retrieve, and start heartbeat monitors alongside deadline monitors.
  • Adds C++ wrapper types, wiring in HealthMonitorBuilder::add_heartbeat_monitor / HealthMonitor::get_heartbeat_monitor, and updates C++ tests/build.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/health_monitoring_lib/rust/worker.rs Passes a shared HMON starting Instant into monitor evaluation and logs heartbeat evaluation errors.
src/health_monitoring_lib/rust/lib.rs Adds heartbeat monitor storage/build/retrieval and includes heartbeat monitors when starting the worker.
src/health_monitoring_lib/rust/heartbeat/mod.rs Introduces the heartbeat module exports and FFI submodule.
src/health_monitoring_lib/rust/heartbeat/heartbeat_state.rs Adds packed atomic heartbeat state representation plus unit tests.
src/health_monitoring_lib/rust/heartbeat/heartbeat_monitor.rs Implements heartbeat monitor builder, evaluation logic, and tests (incl. loom tests).
src/health_monitoring_lib/rust/heartbeat/ffi.rs Adds FFI functions for heartbeat builder creation/destruction and sending heartbeats from C++.
src/health_monitoring_lib/rust/ffi.rs Adds FFI to register heartbeat monitors with the HMON builder and to retrieve heartbeat monitors.
src/health_monitoring_lib/rust/deadline/deadline_monitor.rs Updates evaluator signature and reuses shared time conversion helper.
src/health_monitoring_lib/rust/common.rs Extends MonitorEvaluator to include an HMON starting point and adds time helpers used by heartbeat.
src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp Extends the C++ test to build/get/use a heartbeat monitor.
src/health_monitoring_lib/cpp/include/score/hm/heartbeat/heartbeat_monitor.h Adds the C++ heartbeat monitor and builder API declarations.
src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h Adds heartbeat monitor inclusion and retrieval APIs to C++ HMON.
src/health_monitoring_lib/cpp/heartbeat_monitor.cpp Implements the C++ heartbeat wrapper over Rust FFI calls.
src/health_monitoring_lib/cpp/health_monitor.cpp Wires heartbeat monitor builder/getter calls through to the Rust FFI.
src/health_monitoring_lib/BUILD Adds the new C++ heartbeat source/header to the build.

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

Comment on lines +149 to +172
// Get current timestamp, with offset to HMON time.
let offset = hmon_time_offset(hmon_starting_point, self.monitor_starting_point);
let now = offset + duration_to_u32(hmon_starting_point.elapsed());

// Load current monitor state.
let snapshot = self.heartbeat_state.snapshot();

// Get and recalculate snapshot timestamps.
// IMPORTANT: first heartbeat is obtained when HMON time is unknown.
// It is necessary to:
// - use offset as cycle starting point.
// - get heartbeat snapshot in relation to zero point.
let (start_timestamp, heartbeat_timestamp) = if snapshot.post_init() {
let start_timestamp = snapshot.start_timestamp();
let heartbeat_timestamp = start_timestamp + snapshot.heartbeat_timestamp_offset();
(start_timestamp, heartbeat_timestamp)
} else {
let start_timestamp = offset;
let heartbeat_timestamp = snapshot.heartbeat_timestamp_offset();
(start_timestamp, heartbeat_timestamp)
};

// Get allowed time range as absolute values.
let range = self.range.offset(start_timestamp);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The timestamp math here uses u32 addition (now = offset + duration_to_u32(...), and later start_timestamp + snapshot.heartbeat_timestamp_offset() / self.range.offset(start_timestamp)). These additions can overflow and silently wrap in release builds, leading to incorrect evaluations after long uptimes or large start offsets. Consider using checked/saturating arithmetic (and reporting an error) or keeping timestamps in u64 until the final packing step.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +73
// Check range is valid.
let range_min_ms = self.range.min.as_millis() as u64;
let internal_processing_cycle_ms = internal_processing_cycle.as_millis() as u64;
if range_min_ms * 2 <= internal_processing_cycle_ms {
error!(
"Internal processing cycle duration ({} ms) must be longer than two shortest allowed ranges ({} ms).",
internal_processing_cycle_ms, range_min_ms
);
return Err(HealthMonitorError::InvalidArgument);
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The validation for internal_processing_cycle vs the heartbeat range looks incorrect: with the current condition (range_min_ms * 2 <= internal_processing_cycle_ms) you can still end up with two valid heartbeats occurring between evaluations when internal_processing_cycle_ms > range_min_ms, which will be reported as MultipleHeartbeats even though the beats are in different cycles. This check should enforce that the internal processing/evaluation cycle is strictly shorter than the minimum allowed heartbeat interval (and update the error message accordingly).

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +31
pub extern "C" fn heartbeat_monitor_builder_create(
range_min_ms: u32,
range_max_ms: u32,
heartbeat_monitor_builder_handle_out: *mut FFIHandle,
) -> FFICode {
if heartbeat_monitor_builder_handle_out.is_null() {
return FFICode::NullParameter;
}

let range_min = Duration::from_millis(range_min_ms as u64);
let range_max = Duration::from_millis(range_max_ms as u64);
let range = TimeRange::new(range_min, range_max);

Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

heartbeat_monitor_builder_create constructs TimeRange::new(range_min, range_max) without validating range_min_ms <= range_max_ms. Since TimeRange::new asserts on invalid ranges, passing a bad range from C/C++ would panic across the FFI boundary. Please add an explicit check (mirroring deadline_monitor_builder_add_deadline) and return FFICode::InvalidArgument instead of panicking.

Copilot uses AI. Check for mistakes.
arkjedrz added 2 commits March 3, 2026 13:39
Add heartbeat monitor HMON.
Add C++ interface to heartbeat monitor.
@arkjedrz arkjedrz force-pushed the arkjedrz_heartbeat-monitor-cpp branch from 9d1ba1c to 046bcf4 Compare March 3, 2026 12:39
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 3, 2026 12:39 — with GitHub Actions Inactive
@arkjedrz arkjedrz temporarily deployed to workflow-approval March 3, 2026 12:39 — with GitHub Actions Inactive
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] C++ Heartbeat Monitor API

2 participants