@@ -456,14 +456,15 @@ where
456
456
457
457
pub async fn begin_execute (
458
458
& self ,
459
+ token : CancellationToken ,
459
460
request : ExecuteRequest ,
460
461
) -> Result < ActiveExecution , ExecuteError > {
461
462
use execute_error:: * ;
462
463
463
464
self . select_channel ( request. channel )
464
465
. await
465
466
. context ( CouldNotStartContainerSnafu ) ?
466
- . begin_execute ( request)
467
+ . begin_execute ( token , request)
467
468
. await
468
469
}
469
470
@@ -482,14 +483,15 @@ where
482
483
483
484
pub async fn begin_compile (
484
485
& self ,
486
+ token : CancellationToken ,
485
487
request : CompileRequest ,
486
488
) -> Result < ActiveCompilation , CompileError > {
487
489
use compile_error:: * ;
488
490
489
491
self . select_channel ( request. channel )
490
492
. await
491
493
. context ( CouldNotStartContainerSnafu ) ?
492
- . begin_compile ( request)
494
+ . begin_compile ( token , request)
493
495
. await
494
496
}
495
497
@@ -603,12 +605,14 @@ impl Container {
603
605
& self ,
604
606
request : ExecuteRequest ,
605
607
) -> Result < WithOutput < ExecuteResponse > , ExecuteError > {
608
+ let token = Default :: default ( ) ;
609
+
606
610
let ActiveExecution {
607
611
task,
608
612
stdin_tx,
609
613
stdout_rx,
610
614
stderr_rx,
611
- } = self . begin_execute ( request) . await ?;
615
+ } = self . begin_execute ( token , request) . await ?;
612
616
613
617
drop ( stdin_tx) ;
614
618
WithOutput :: try_absorb ( task, stdout_rx, stderr_rx) . await
@@ -617,6 +621,7 @@ impl Container {
617
621
#[ instrument( skip_all) ]
618
622
async fn begin_execute (
619
623
& self ,
624
+ token : CancellationToken ,
620
625
request : ExecuteRequest ,
621
626
) -> Result < ActiveExecution , ExecuteError > {
622
627
use execute_error:: * ;
@@ -642,7 +647,7 @@ impl Container {
642
647
stdout_rx,
643
648
stderr_rx,
644
649
} = self
645
- . spawn_cargo_task ( execute_cargo)
650
+ . spawn_cargo_task ( token , execute_cargo)
646
651
. await
647
652
. context ( CouldNotStartCargoSnafu ) ?;
648
653
@@ -673,18 +678,21 @@ impl Container {
673
678
& self ,
674
679
request : CompileRequest ,
675
680
) -> Result < WithOutput < CompileResponse > , CompileError > {
681
+ let token = Default :: default ( ) ;
682
+
676
683
let ActiveCompilation {
677
684
task,
678
685
stdout_rx,
679
686
stderr_rx,
680
- } = self . begin_compile ( request) . await ?;
687
+ } = self . begin_compile ( token , request) . await ?;
681
688
682
689
WithOutput :: try_absorb ( task, stdout_rx, stderr_rx) . await
683
690
}
684
691
685
692
#[ instrument( skip_all) ]
686
693
async fn begin_compile (
687
694
& self ,
695
+ token : CancellationToken ,
688
696
request : CompileRequest ,
689
697
) -> Result < ActiveCompilation , CompileError > {
690
698
use compile_error:: * ;
@@ -715,7 +723,7 @@ impl Container {
715
723
stdout_rx,
716
724
stderr_rx,
717
725
} = self
718
- . spawn_cargo_task ( execute_cargo)
726
+ . spawn_cargo_task ( token , execute_cargo)
719
727
. await
720
728
. context ( CouldNotStartCargoSnafu ) ?;
721
729
@@ -761,6 +769,7 @@ impl Container {
761
769
762
770
async fn spawn_cargo_task (
763
771
& self ,
772
+ token : CancellationToken ,
764
773
execute_cargo : ExecuteCommandRequest ,
765
774
) -> Result < SpawnCargo , SpawnCargoError > {
766
775
use spawn_cargo_error:: * ;
@@ -777,10 +786,19 @@ impl Container {
777
786
778
787
let task = tokio:: spawn ( {
779
788
async move {
789
+ let mut already_cancelled = false ;
780
790
let mut stdin_open = true ;
781
791
782
792
loop {
783
793
select ! {
794
+ ( ) = token. cancelled( ) , if !already_cancelled => {
795
+ already_cancelled = true ;
796
+
797
+ let msg = CoordinatorMessage :: Kill ;
798
+ trace!( "processing {msg:?}" ) ;
799
+ to_worker_tx. send( msg) . await . context( KillSnafu ) ?;
800
+ } ,
801
+
784
802
stdin = stdin_rx. recv( ) , if stdin_open => {
785
803
let msg = match stdin {
786
804
Some ( stdin) => {
@@ -952,6 +970,9 @@ pub enum SpawnCargoError {
952
970
953
971
#[ snafu( display( "Unable to send stdin message" ) ) ]
954
972
Stdin { source : MultiplexedSenderError } ,
973
+
974
+ #[ snafu( display( "Unable to send kill message" ) ) ]
975
+ Kill { source : MultiplexedSenderError } ,
955
976
}
956
977
957
978
#[ derive( Debug , Clone ) ]
@@ -1787,12 +1808,13 @@ mod tests {
1787
1808
..ARBITRARY_EXECUTE_REQUEST
1788
1809
} ;
1789
1810
1811
+ let token = Default :: default ( ) ;
1790
1812
let ActiveExecution {
1791
1813
task,
1792
1814
stdin_tx,
1793
1815
stdout_rx,
1794
1816
stderr_rx,
1795
- } = coordinator. begin_execute ( request) . await . unwrap ( ) ;
1817
+ } = coordinator. begin_execute ( token , request) . await . unwrap ( ) ;
1796
1818
1797
1819
stdin_tx. send ( "this is stdin\n " . into ( ) ) . await . unwrap ( ) ;
1798
1820
// Purposefully not dropping stdin_tx early -- a user might forget
@@ -1836,12 +1858,13 @@ mod tests {
1836
1858
..ARBITRARY_EXECUTE_REQUEST
1837
1859
} ;
1838
1860
1861
+ let token = Default :: default ( ) ;
1839
1862
let ActiveExecution {
1840
1863
task,
1841
1864
stdin_tx,
1842
1865
stdout_rx,
1843
1866
stderr_rx,
1844
- } = coordinator. begin_execute ( request) . await . unwrap ( ) ;
1867
+ } = coordinator. begin_execute ( token , request) . await . unwrap ( ) ;
1845
1868
1846
1869
for i in 0 ..3 {
1847
1870
stdin_tx. send ( format ! ( "line {i}\n " ) ) . await . unwrap ( ) ;
@@ -1870,6 +1893,62 @@ mod tests {
1870
1893
Ok ( ( ) )
1871
1894
}
1872
1895
1896
+ #[ tokio:: test]
1897
+ #[ snafu:: report]
1898
+ async fn execute_kill ( ) -> Result < ( ) > {
1899
+ let coordinator = new_coordinator ( ) . await ;
1900
+
1901
+ let request = ExecuteRequest {
1902
+ code : r#"
1903
+ fn main() {
1904
+ println!("Before");
1905
+ loop {
1906
+ std::thread::sleep(std::time::Duration::from_secs(1));
1907
+ }
1908
+ println!("After");
1909
+ }
1910
+ "#
1911
+ . into ( ) ,
1912
+ ..ARBITRARY_EXECUTE_REQUEST
1913
+ } ;
1914
+
1915
+ let token = CancellationToken :: new ( ) ;
1916
+ let ActiveExecution {
1917
+ task,
1918
+ stdin_tx : _,
1919
+ mut stdout_rx,
1920
+ stderr_rx,
1921
+ } = coordinator
1922
+ . begin_execute ( token. clone ( ) , request)
1923
+ . await
1924
+ . unwrap ( ) ;
1925
+
1926
+ // Wait for some output before killing
1927
+ let early_stdout = stdout_rx. recv ( ) . await . unwrap ( ) ;
1928
+
1929
+ token. cancel ( ) ;
1930
+
1931
+ let WithOutput {
1932
+ response,
1933
+ stdout,
1934
+ stderr,
1935
+ } = WithOutput :: try_absorb ( task, stdout_rx, stderr_rx)
1936
+ . with_timeout ( )
1937
+ . await
1938
+ . unwrap ( ) ;
1939
+
1940
+ assert ! ( !response. success, "{stderr}" ) ;
1941
+ assert_contains ! ( response. exit_detail, "kill" ) ;
1942
+
1943
+ assert_contains ! ( early_stdout, "Before" ) ;
1944
+ assert_not_contains ! ( stdout, "Before" ) ;
1945
+ assert_not_contains ! ( stdout, "After" ) ;
1946
+
1947
+ coordinator. shutdown ( ) . await ?;
1948
+
1949
+ Ok ( ( ) )
1950
+ }
1951
+
1873
1952
const HELLO_WORLD_CODE : & str = r#"fn main() { println!("Hello World!"); }"# ;
1874
1953
1875
1954
const ARBITRARY_COMPILE_REQUEST : CompileRequest = CompileRequest {
@@ -1914,11 +1993,12 @@ mod tests {
1914
1993
..ARBITRARY_COMPILE_REQUEST
1915
1994
} ;
1916
1995
1996
+ let token = Default :: default ( ) ;
1917
1997
let ActiveCompilation {
1918
1998
task,
1919
1999
stdout_rx,
1920
2000
stderr_rx,
1921
- } = coordinator. begin_compile ( req) . await . unwrap ( ) ;
2001
+ } = coordinator. begin_compile ( token , req) . await . unwrap ( ) ;
1922
2002
1923
2003
let WithOutput {
1924
2004
response,
0 commit comments