@@ -2,29 +2,30 @@ use crate::{api, controller, system};
22use futures:: { FutureExt , StreamExt , stream:: FuturesUnordered } ;
33use pulsebeam_runtime:: { actor, net, rt} ;
44use std:: { net:: SocketAddr , sync:: Arc , time:: Duration } ;
5+ use tokio_util:: sync:: CancellationToken ;
56use tower_http:: cors:: { AllowOrigin , CorsLayer } ;
67
78pub async fn run (
8- cpu_rt : rt:: Runtime ,
9+ shutdown : CancellationToken ,
10+ cpu_rt : & rt:: Runtime ,
911 external_addr : SocketAddr ,
1012 unified_socket : net:: UnifiedSocket < ' static > ,
1113 http_addr : SocketAddr ,
1214) -> anyhow:: Result < ( ) > {
13- // Configure CORS
1415 let cors = CorsLayer :: very_permissive ( )
1516 . allow_origin ( AllowOrigin :: mirror_request ( ) )
1617 . expose_headers ( [ hyper:: header:: LOCATION ] )
1718 . max_age ( Duration :: from_secs ( 86400 ) ) ;
1819
19- // Spawn system and controller actors
2020 let mut join_set = FuturesUnordered :: new ( ) ;
2121
2222 let ( system_ctx, system_join) = system:: SystemContext :: spawn ( unified_socket) ;
2323 join_set. push ( system_join. map ( |_| ( ) ) . boxed ( ) ) ;
2424
2525 let ( controller_ready_tx, controller_ready_rx) = tokio:: sync:: oneshot:: channel ( ) ;
2626
27- // TODO: handle cleanup
27+ // Spawn controller on CPU runtime
28+ let shutdown_for_controller = shutdown. clone ( ) ;
2829 cpu_rt. spawn ( async move {
2930 let controller_actor = controller:: ControllerActor :: new (
3031 system_ctx,
@@ -33,28 +34,52 @@ pub async fn run(
3334 ) ;
3435 let ( controller_handle, controller_join) =
3536 actor:: spawn ( controller_actor, actor:: RunnerConfig :: default ( ) ) ;
36- controller_ready_tx. send ( controller_handle) . unwrap ( ) ;
37+ let _ = controller_ready_tx. send ( controller_handle) ;
3738 tracing:: debug!( "controller is ready" ) ;
38- controller_join. await ;
39+
40+ tokio:: select! {
41+ _ = controller_join => { }
42+ _ = shutdown_for_controller. cancelled( ) => {
43+ tracing:: debug!( "controller received shutdown" ) ;
44+ }
45+ }
3946 } ) ;
4047
4148 tracing:: debug!( "waiting on controller to be ready" ) ;
4249 let controller_handle = controller_ready_rx. await ?;
43- // Set up signaling router
50+
51+ // HTTP API
4452 let api_cfg = api:: ApiConfig {
4553 base_path : "/api/v1" . to_string ( ) ,
4654 default_host : http_addr. to_string ( ) ,
4755 } ;
4856 let router = api:: router ( controller_handle, api_cfg) . layer ( cors) ;
49- tracing:: debug!( "listening on {http_addr}" ) ;
5057
58+ let shutdown_for_http = shutdown. clone ( ) ;
5159 let signaling = async move {
5260 let listener = tokio:: net:: TcpListener :: bind ( http_addr) . await . unwrap ( ) ;
53- axum:: serve ( listener, router) . await . unwrap ( ) ;
61+ tracing:: debug!( "listening on {http_addr}" ) ;
62+ tokio:: select! {
63+ res = axum:: serve( listener, router) => {
64+ if let Err ( e) = res {
65+ tracing:: error!( "http server error: {e}" ) ;
66+ }
67+ }
68+ _ = shutdown_for_http. cancelled( ) => {
69+ tracing:: info!( "http server shutting down" ) ;
70+ }
71+ }
5472 } ;
73+
5574 join_set. push ( tokio:: spawn ( signaling) . map ( |_| ( ) ) . boxed ( ) ) ;
5675
57- // Wait for all tasks to complete
58- while join_set. next ( ) . await . is_some ( ) { }
76+ // Wait for all tasks to complete OR shutdown
77+ tokio:: select! {
78+ _ = async { while join_set. next( ) . await . is_some( ) { } } => { }
79+ _ = shutdown. cancelled( ) => {
80+ tracing:: info!( "node received shutdown" ) ;
81+ }
82+ }
83+
5984 Ok ( ( ) )
6085}
0 commit comments