@@ -67,12 +67,43 @@ fn retain_antares_mounts() -> bool {
6767 }
6868}
6969
70+ fn antares_unmount_grace_duration ( ) -> Duration {
71+ const DEFAULT_MS : u64 = 150 ;
72+ match std:: env:: var ( "ORION_ANTARES_UNMOUNT_GRACE_MS" ) {
73+ Ok ( raw) => match raw. trim ( ) . parse :: < u64 > ( ) {
74+ Ok ( ms) => Duration :: from_millis ( ms. clamp ( 0 , 3_000 ) ) ,
75+ Err ( _) => {
76+ tracing:: warn!(
77+ value = %raw,
78+ default_ms = DEFAULT_MS ,
79+ "invalid ORION_ANTARES_UNMOUNT_GRACE_MS, using default"
80+ ) ;
81+ Duration :: from_millis ( DEFAULT_MS )
82+ }
83+ } ,
84+ Err ( _) => Duration :: from_millis ( DEFAULT_MS ) ,
85+ }
86+ }
87+
7088async fn cleanup_antares_mount (
7189 task_id : & str ,
7290 mount_id : & str ,
7391 mount_point : Option < & str > ,
7492 reason : & str ,
7593) {
94+ let grace = antares_unmount_grace_duration ( ) ;
95+ if !grace. is_zero ( ) {
96+ tracing:: info!(
97+ "[Task {}] Waiting {:?} before Antares mount cleanup (mount_id={}, mountpoint={}, reason={})" ,
98+ task_id,
99+ grace,
100+ mount_id,
101+ mount_point. unwrap_or( "<unknown>" ) ,
102+ reason,
103+ ) ;
104+ tokio:: time:: sleep ( grace) . await ;
105+ }
106+
76107 match unmount_antares_fs ( mount_id) . await {
77108 Ok ( true ) => tracing:: info!(
78109 "[Task {}] Cleaned Antares mount (mount_id={}, mountpoint={}, reason={})" ,
@@ -1369,6 +1400,7 @@ mod tests {
13691400 use std:: {
13701401 fs,
13711402 path:: { Path , PathBuf } ,
1403+ time:: Duration ,
13721404 } ;
13731405
13741406 use api_model:: buck2:: { status:: Status , types:: ProjectRelativePath } ;
@@ -1378,8 +1410,9 @@ mod tests {
13781410 use tokio:: sync:: mpsc;
13791411
13801412 use super :: {
1381- finish_without_build_if_no_targets, get_build_targets, get_repo_targets,
1382- remap_repo_local_change_paths, retain_antares_mounts, validate_project_root_exists,
1413+ antares_unmount_grace_duration, finish_without_build_if_no_targets, get_build_targets,
1414+ get_repo_targets, remap_repo_local_change_paths, retain_antares_mounts,
1415+ validate_project_root_exists,
13831416 } ;
13841417
13851418 struct JsonlCleanupGuard {
@@ -1459,6 +1492,16 @@ mod tests {
14591492 }
14601493 }
14611494
1495+ fn set_antares_unmount_grace_env ( value : Option < & str > ) {
1496+ // SAFETY: these tests are marked serial and only mutate process env inside the test.
1497+ unsafe {
1498+ match value {
1499+ Some ( value) => std:: env:: set_var ( "ORION_ANTARES_UNMOUNT_GRACE_MS" , value) ,
1500+ None => std:: env:: remove_var ( "ORION_ANTARES_UNMOUNT_GRACE_MS" ) ,
1501+ }
1502+ }
1503+ }
1504+
14621505 #[ test]
14631506 #[ serial]
14641507 fn test_retain_antares_mounts_defaults_to_false ( ) {
@@ -1487,6 +1530,36 @@ mod tests {
14871530 set_mount_retention_env ( None ) ;
14881531 }
14891532
1533+ #[ test]
1534+ #[ serial]
1535+ fn test_antares_unmount_grace_duration_defaults_to_150ms ( ) {
1536+ set_antares_unmount_grace_env ( None ) ;
1537+ assert_eq ! ( antares_unmount_grace_duration( ) , Duration :: from_millis( 150 ) ) ;
1538+ }
1539+
1540+ #[ test]
1541+ #[ serial]
1542+ fn test_antares_unmount_grace_duration_accepts_explicit_value ( ) {
1543+ set_antares_unmount_grace_env ( Some ( "275" ) ) ;
1544+ assert_eq ! ( antares_unmount_grace_duration( ) , Duration :: from_millis( 275 ) ) ;
1545+ set_antares_unmount_grace_env ( None ) ;
1546+ }
1547+
1548+ #[ test]
1549+ #[ serial]
1550+ fn test_antares_unmount_grace_duration_clamps_and_falls_back ( ) {
1551+ set_antares_unmount_grace_env ( Some ( "50000" ) ) ;
1552+ assert_eq ! (
1553+ antares_unmount_grace_duration( ) ,
1554+ Duration :: from_millis( 3000 )
1555+ ) ;
1556+
1557+ set_antares_unmount_grace_env ( Some ( "not-a-number" ) ) ;
1558+ assert_eq ! ( antares_unmount_grace_duration( ) , Duration :: from_millis( 150 ) ) ;
1559+
1560+ set_antares_unmount_grace_env ( None ) ;
1561+ }
1562+
14901563 #[ tokio:: test]
14911564 #[ serial]
14921565 async fn test_get_build_targets_detects_root_relative_subproject_source_change ( ) {
0 commit comments