11use axum;
22use bytes:: Bytes ;
33use dashmap:: DashMap ;
4+ use lazy_static:: lazy_static;
45use ntex:: {
56 client:: ClientResponse ,
67 io:: Sealed ,
@@ -14,9 +15,36 @@ use std::{
1415 time:: Duration ,
1516} ;
1617use tempfile:: NamedTempFile ;
17- use tokio:: { net:: TcpListener , sync:: oneshot} ;
18+ use tokio:: {
19+ net:: TcpListener ,
20+ sync:: { oneshot, Semaphore } ,
21+ } ;
1822use tracing:: { info, warn} ;
1923
24+ lazy_static ! {
25+ /// Limits concurrent test routers to avoid hitting the OS open-file-descriptor limit.
26+ /// Hive Router and the subgraphs opens about 24 file descriptors per instance (tokio
27+ /// for the event queue, dyn libs, port bindings, domain sockets), so we divide the system's
28+ /// `RLIMIT_NOFILE` by that number to get a safe concurrency limit. Increasing the OS ulimit
29+ /// will increase the concurrency of tests.
30+ static ref CONCURRENCY_SEMAPHORE : Arc <Semaphore > = {
31+ let limit = {
32+ let mut rlimit = libc:: rlimit {
33+ rlim_cur: 0 ,
34+ rlim_max: 0 ,
35+ } ;
36+ let nofile = if unsafe { libc:: getrlimit( libc:: RLIMIT_NOFILE , & mut rlimit) } == 0 {
37+ rlimit. rlim_cur as usize
38+ } else {
39+ 256 // fallback, about the default ulimit on many sysstms
40+ } ;
41+ ( nofile / 24 ) . max( 1 )
42+ } ;
43+ info!( "Concurrency semaphore initialized with {} permits" , limit) ;
44+ Arc :: new( Semaphore :: new( limit) )
45+ } ;
46+ }
47+
2048use hive_router:: {
2149 background_tasks:: BackgroundTasksManager , configure_app_from_config, configure_ntex_app,
2250 init_rustls_crypto_provider, telemetry:: Telemetry ,
@@ -393,6 +421,11 @@ pub struct TestRouter<'subgraphs, State> {
393421
394422impl < ' subgraphs > TestRouter < ' subgraphs , Built > {
395423 pub async fn start ( mut self ) -> TestRouter < ' subgraphs , Started > {
424+ let permit = Arc :: clone ( & CONCURRENCY_SEMAPHORE )
425+ . acquire_owned ( )
426+ . await
427+ . expect ( "concurrency semaphore closed" ) ;
428+
396429 init_rustls_crypto_provider ( ) ;
397430 let config = self . config . take ( ) . unwrap ( ) ;
398431 let ( telemetry, subscriber) =
@@ -467,6 +500,7 @@ impl<'subgraphs> TestRouter<'subgraphs, Built> {
467500
468501 let mut hold_until_drop = self . _hold_until_drop ;
469502 hold_until_drop. push ( Box :: new ( subscription_guard) ) ;
503+ hold_until_drop. push ( Box :: new ( permit) ) ;
470504
471505 TestRouter {
472506 graphql_path : self . graphql_path ,
0 commit comments