@@ -392,18 +392,43 @@ struct ServiceAccountInfo {
392392struct BackgroundHealStatusResponse {
393393 #[ serde( default ) ]
394394 bitrot_start_time : Option < String > ,
395+ #[ serde( default ) ]
396+ bitrot_start_cycle : u64 ,
397+ #[ serde( default ) ]
398+ current_scan_mode : Option < u8 > ,
399+ #[ serde( default ) ]
400+ heal_queue_length : u64 ,
401+ #[ serde( default ) ]
402+ heal_active_tasks : u64 ,
395403}
396404
397405impl From < BackgroundHealStatusResponse > for HealStatus {
398406 fn from ( response : BackgroundHealStatusResponse ) -> Self {
407+ let scan_mode = background_heal_scan_mode ( response. current_scan_mode ) ;
408+ let legacy_healing = scan_mode. is_none ( ) && response. bitrot_start_time . is_some ( ) ;
399409 Self {
400- healing : response. bitrot_start_time . is_some ( ) ,
410+ healing : matches ! ( scan_mode, Some ( HealScanMode :: Deep ) )
411+ || response. heal_queue_length > 0
412+ || response. heal_active_tasks > 0
413+ || legacy_healing,
401414 started : response. bitrot_start_time ,
415+ scan_mode,
416+ scan_cycle : response. bitrot_start_cycle ,
417+ heal_queue_length : response. heal_queue_length ,
418+ heal_active_tasks : response. heal_active_tasks ,
402419 ..Default :: default ( )
403420 }
404421 }
405422}
406423
424+ fn background_heal_scan_mode ( scan_mode : Option < u8 > ) -> Option < HealScanMode > {
425+ match scan_mode {
426+ Some ( 1 ) => Some ( HealScanMode :: Normal ) ,
427+ Some ( 2 ) => Some ( HealScanMode :: Deep ) ,
428+ _ => None ,
429+ }
430+ }
431+
407432#[ derive( Debug , Serialize ) ]
408433struct RustfsHealOptions {
409434 recursive : bool ,
@@ -1198,16 +1223,58 @@ mod tests {
11981223 fn test_background_heal_status_response_maps_to_heal_status ( ) {
11991224 let status = HealStatus :: from ( BackgroundHealStatusResponse {
12001225 bitrot_start_time : Some ( "2026-04-19T10:00:00Z" . to_string ( ) ) ,
1226+ bitrot_start_cycle : 42 ,
1227+ current_scan_mode : Some ( 2 ) ,
1228+ heal_queue_length : 3 ,
1229+ heal_active_tasks : 1 ,
12011230 } ) ;
12021231
12031232 assert ! ( status. healing) ;
12041233 assert_eq ! ( status. started. as_deref( ) , Some ( "2026-04-19T10:00:00Z" ) ) ;
1234+ assert_eq ! ( status. scan_mode, Some ( HealScanMode :: Deep ) ) ;
1235+ assert_eq ! ( status. scan_cycle, 42 ) ;
1236+ assert_eq ! ( status. heal_queue_length, 3 ) ;
1237+ assert_eq ! ( status. heal_active_tasks, 1 ) ;
12051238
12061239 let idle = HealStatus :: from ( BackgroundHealStatusResponse {
12071240 bitrot_start_time : None ,
1241+ bitrot_start_cycle : 0 ,
1242+ current_scan_mode : Some ( 1 ) ,
1243+ heal_queue_length : 0 ,
1244+ heal_active_tasks : 0 ,
12081245 } ) ;
12091246 assert ! ( !idle. healing) ;
1247+ assert_eq ! ( idle. scan_mode, Some ( HealScanMode :: Normal ) ) ;
12101248 assert ! ( idle. started. is_none( ) ) ;
1249+
1250+ let completed = HealStatus :: from ( BackgroundHealStatusResponse {
1251+ bitrot_start_time : Some ( "2026-04-19T10:00:00Z" . to_string ( ) ) ,
1252+ bitrot_start_cycle : 42 ,
1253+ current_scan_mode : Some ( 1 ) ,
1254+ heal_queue_length : 0 ,
1255+ heal_active_tasks : 0 ,
1256+ } ) ;
1257+ assert ! ( !completed. healing) ;
1258+ assert_eq ! ( completed. scan_mode, Some ( HealScanMode :: Normal ) ) ;
1259+ assert_eq ! ( completed. started. as_deref( ) , Some ( "2026-04-19T10:00:00Z" ) ) ;
1260+
1261+ let legacy = HealStatus :: from ( BackgroundHealStatusResponse {
1262+ bitrot_start_time : Some ( "2026-04-19T10:00:00Z" . to_string ( ) ) ,
1263+ bitrot_start_cycle : 0 ,
1264+ current_scan_mode : None ,
1265+ heal_queue_length : 0 ,
1266+ heal_active_tasks : 0 ,
1267+ } ) ;
1268+ assert ! ( legacy. healing) ;
1269+
1270+ let active = HealStatus :: from ( BackgroundHealStatusResponse {
1271+ bitrot_start_time : None ,
1272+ bitrot_start_cycle : 0 ,
1273+ current_scan_mode : None ,
1274+ heal_queue_length : 0 ,
1275+ heal_active_tasks : 1 ,
1276+ } ) ;
1277+ assert ! ( active. healing) ;
12111278 }
12121279
12131280 #[ test]
@@ -1222,14 +1289,20 @@ mod tests {
12221289
12231290 #[ tokio:: test]
12241291 async fn test_heal_status_uses_background_heal_status_endpoint ( ) {
1225- let ( endpoint, receiver, handle) =
1226- start_admin_test_server ( "200 OK" , r#"{"bitrotStartTime":"2026-04-19T10:00:00Z"}"# ) ;
1292+ let ( endpoint, receiver, handle) = start_admin_test_server (
1293+ "200 OK" ,
1294+ r#"{"bitrotStartTime":"2026-04-19T10:00:00Z","bitrotStartCycle":42,"currentScanMode":2,"healQueueLength":3,"healActiveTasks":1}"# ,
1295+ ) ;
12271296 let client = admin_client_for_endpoint ( & endpoint) ;
12281297
12291298 let status = client. heal_status ( ) . await . expect ( "heal status request" ) ;
12301299
12311300 assert ! ( status. healing) ;
12321301 assert_eq ! ( status. started. as_deref( ) , Some ( "2026-04-19T10:00:00Z" ) ) ;
1302+ assert_eq ! ( status. scan_mode, Some ( HealScanMode :: Deep ) ) ;
1303+ assert_eq ! ( status. scan_cycle, 42 ) ;
1304+ assert_eq ! ( status. heal_queue_length, 3 ) ;
1305+ assert_eq ! ( status. heal_active_tasks, 1 ) ;
12331306
12341307 let request = receiver. recv ( ) . expect ( "captured request" ) ;
12351308 assert_eq ! ( request. method, "POST" ) ;
0 commit comments