@@ -28,6 +28,28 @@ impl MetricsWebhookSender {
2828 }
2929 }
3030
31+ pub fn metrics_changed (
32+ metrics : & HashMap < String , f64 > ,
33+ last_sent_metrics : & HashMap < String , f64 > ,
34+ ) -> bool {
35+ if metrics. len ( ) != last_sent_metrics. len ( ) {
36+ return true ;
37+ }
38+
39+ // FP imprecision fix
40+ const EPSILON : f64 = 1e-10 ;
41+
42+ for ( key, value) in metrics {
43+ match last_sent_metrics. get ( key) {
44+ None => return true ,
45+ Some ( last_value) if ( last_value - value) . abs ( ) > EPSILON => return true ,
46+ _ => continue ,
47+ }
48+ }
49+
50+ false
51+ }
52+
3153 pub async fn run ( & mut self ) -> Result < ( ) > {
3254 let mut interval = interval ( Duration :: from_secs ( 15 ) ) ;
3355 loop {
@@ -37,7 +59,7 @@ impl MetricsWebhookSender {
3759 . metrics_store
3860 . get_aggregate_metrics_for_all_tasks ( ) ;
3961
40- if metrics != self . last_sent_metrics {
62+ if Self :: metrics_changed ( & metrics, & self . last_sent_metrics ) {
4163 info ! ( "Sending {} metrics via webhook" , metrics. len( ) ) ;
4264 for plugin in & self . webhook_plugins {
4365 let _ = plugin
@@ -50,3 +72,22 @@ impl MetricsWebhookSender {
5072 }
5173 }
5274}
75+
76+ #[ cfg( test) ]
77+ mod tests {
78+ use super :: * ;
79+
80+ #[ tokio:: test]
81+ async fn test_metrics_changed ( ) {
82+ let mut metrics = HashMap :: new ( ) ;
83+ metrics. insert ( "test_metric" . to_string ( ) , 1.0 ) ;
84+ metrics. insert ( "metric_2" . to_string ( ) , 2.0 ) ;
85+
86+ let mut last_sent_metrics = HashMap :: new ( ) ;
87+ last_sent_metrics. insert ( "metric_2" . to_string ( ) , 2.0 ) ;
88+ last_sent_metrics. insert ( "test_metric" . to_string ( ) , 1.0 ) ;
89+
90+ let metrics_changed = MetricsWebhookSender :: metrics_changed ( & metrics, & last_sent_metrics) ;
91+ assert ! ( !metrics_changed) ;
92+ }
93+ }
0 commit comments