@@ -33,10 +33,14 @@ pub struct RelayConfig {
3333 /// Our hostname which we advertise to other origins.
3434 /// We use QUIC, so the certificate must be valid for this address.
3535 pub node : Option < Url > ,
36+
37+ /// The public URL we advertise to other origins.
38+ pub public_url : Option < Url > ,
3639}
3740
3841/// MoQ Relay server.
3942pub struct Relay {
43+ public_url : Option < Url > ,
4044 quic : quic:: Endpoint ,
4145 announce_url : Option < Url > ,
4246 mlog_dir : Option < PathBuf > ,
@@ -85,6 +89,7 @@ impl Relay {
8589 } ) ;
8690
8791 Ok ( Self {
92+ public_url : config. public_url ,
8893 quic,
8994 announce_url : config. announce ,
9095 mlog_dir : config. mlog_dir ,
@@ -105,7 +110,7 @@ impl Relay {
105110 let mut signal_int =
106111 tokio:: signal:: unix:: signal ( tokio:: signal:: unix:: SignalKind :: interrupt ( ) ) ?;
107112
108- let ( signal_tx, signal_rx) = broadcast:: channel :: < SessionMigration > ( 16 ) ;
113+ let ( signal_tx, mut signal_rx) = broadcast:: channel :: < SessionMigration > ( 16 ) ;
109114
110115 // Get server address early for the shutdown signal
111116 let server_addr = self
@@ -114,7 +119,12 @@ impl Relay {
114119 . as_ref ( )
115120 . context ( "missing TLS certificate" ) ?
116121 . local_addr ( ) ?;
117- let shutdown_uri = format ! ( "https://{}" , server_addr) ;
122+ // FIXME(itzmanish): this gives [::]:4433, which is not a valid URL
123+ let shutdown_uri = if let Some ( public_url) = & self . public_url {
124+ public_url. clone ( ) . into ( )
125+ } else {
126+ format ! ( "https://{}" , server_addr)
127+ } ;
118128
119129 // Spawn task to listen for SIGTERM and broadcast shutdown
120130 let signal_tx_clone = signal_tx. clone ( ) ;
@@ -148,8 +158,7 @@ impl Relay {
148158
149159 // Start the remotes producer task, if any
150160 let remotes = self . remotes . map ( |( producer, consumer) | {
151- let signal_rx = signal_rx. resubscribe ( ) ;
152- tasks. push ( producer. run ( signal_rx) . boxed ( ) ) ;
161+ tasks. push ( producer. run ( ) . boxed ( ) ) ;
153162 consumer
154163 } ) ;
155164
@@ -166,10 +175,13 @@ impl Relay {
166175 . context ( "failed to establish forward connection" ) ?;
167176
168177 // Create the MoQ session over the connection
169- let ( session, publisher, subscriber) =
170- moq_transport:: session:: Session :: connect ( session, None )
171- . await
172- . context ( "failed to establish forward session" ) ?;
178+ let ( session, publisher, subscriber) = moq_transport:: session:: Session :: connect (
179+ session,
180+ None ,
181+ Some ( signal_tx_clone. subscribe ( ) ) ,
182+ )
183+ . await
184+ . context ( "failed to establish forward session" ) ?;
173185
174186 // Create a normal looking session, except we never forward or register announces.
175187 let session = Session {
@@ -184,15 +196,7 @@ impl Relay {
184196
185197 let forward_producer = session. producer . clone ( ) ;
186198
187- tasks. push (
188- async move {
189- session
190- . run ( signal_tx_clone. subscribe ( ) )
191- . await
192- . context ( "forwarding failed" )
193- }
194- . boxed ( ) ,
195- ) ;
199+ tasks. push ( async move { session. run ( ) . await . context ( "forwarding failed" ) } . boxed ( ) ) ;
196200
197201 forward_producer
198202 } else {
@@ -202,7 +206,6 @@ impl Relay {
202206 // Start the QUIC server loop
203207 let mut server = self . quic . server . context ( "missing TLS certificate" ) ?;
204208 log:: info!( "listening on {}" , server. local_addr( ) ?) ;
205- let mut cloned_signal_rx = signal_rx. resubscribe ( ) ;
206209
207210 loop {
208211 tokio:: select! {
@@ -218,12 +221,12 @@ impl Relay {
218221 let remotes = remotes. clone( ) ;
219222 let forward = forward_producer. clone( ) ;
220223 let api = self . api. clone( ) ;
221- let session_signal_rx = signal_rx . resubscribe ( ) ;
224+ let session_signal_rx = signal_tx_clone . subscribe ( ) ;
222225
223226 // Spawn a new task to handle the connection
224227 tasks. push( async move {
225228 // Create the MoQ session over the connection (setup handshake etc)
226- let ( session, publisher, subscriber) = match moq_transport:: session:: Session :: accept( conn, mlog_path) . await {
229+ let ( session, publisher, subscriber) = match moq_transport:: session:: Session :: accept( conn, mlog_path, Some ( session_signal_rx ) ) . await {
227230 Ok ( session) => session,
228231 Err ( err) => {
229232 log:: warn!( "failed to accept MoQ session: {}" , err) ;
@@ -238,26 +241,35 @@ impl Relay {
238241 consumer: subscriber. map( |subscriber| Consumer :: new( subscriber, locals, api, forward) ) ,
239242 } ;
240243
241- if let Err ( err) = session. run( session_signal_rx ) . await {
244+ if let Err ( err) = session. run( ) . await {
242245 log:: warn!( "failed to run MoQ session: {}" , err) ;
243246 }
244247
245248 Ok ( ( ) )
246249 } . boxed( ) ) ;
247250 } ,
248251 res = tasks. next( ) , if !tasks. is_empty( ) => res. unwrap( ) ?,
249- _ = cloned_signal_rx. recv( ) => {
250- log:: info!( "received shutdown signal, shutting down. Active tasks: {}" , tasks. len( ) ) ;
251- // set a timeout for waiting for tasks to be empty
252- // FIXME(itzmanish): make this configurable and revisit
253- let timeout = tokio:: time:: timeout( tokio:: time:: Duration :: from_secs( 20 ) , async move {
254- while !tasks. is_empty( ) {
255- // sleep 500ms before checking again
256- tokio:: time:: sleep( tokio:: time:: Duration :: from_millis( 500 ) ) . await ;
252+ _ = signal_rx. recv( ) => {
253+ log:: info!( "received shutdown signal, waiting for {} active tasks to complete" , tasks. len( ) ) ;
254+
255+ // Give sessions a moment to send GOAWAY messages
256+ tokio:: time:: sleep( tokio:: time:: Duration :: from_millis( 200 ) ) . await ;
257+
258+ // Stop accepting new connections and wait for existing tasks to complete
259+ log:: info!( "draining {} remaining tasks..." , tasks. len( ) ) ;
260+ let shutdown_timeout = tokio:: time:: Duration :: from_secs( 20 ) ;
261+ let result = tokio:: time:: timeout( shutdown_timeout, async {
262+ // Actually poll tasks to completion
263+ while let Some ( res) = tasks. next( ) . await {
264+ if let Err ( e) = res {
265+ log:: warn!( "task failed during shutdown: {:?}" , e) ;
266+ }
257267 }
258- } ) ;
259- if let Err ( e) = timeout. await {
260- log:: warn!( "timed out waiting for tasks to be empty: {}" , e) ;
268+ } ) . await ;
269+
270+ match result {
271+ Ok ( _) => log:: info!( "all tasks completed successfully" ) ,
272+ Err ( _) => log:: warn!( "timed out waiting for tasks after {}s" , shutdown_timeout. as_secs( ) ) ,
261273 }
262274 break Ok ( ( ) ) ;
263275 }
0 commit comments