@@ -57,6 +57,7 @@ pub struct Http<B = ::Chunk> {
57
57
max_buf_size : Option < usize > ,
58
58
keep_alive : bool ,
59
59
pipeline : bool ,
60
+ sleep_on_errors : bool ,
60
61
_marker : PhantomData < B > ,
61
62
}
62
63
@@ -102,6 +103,9 @@ pub struct AddrIncoming {
102
103
addr : SocketAddr ,
103
104
keep_alive_timeout : Option < Duration > ,
104
105
listener : TcpListener ,
106
+ handle : Handle ,
107
+ sleep_on_errors : bool ,
108
+ timeout : Option < Timeout > ,
105
109
}
106
110
107
111
/// A future binding a connection with a Service.
@@ -144,6 +148,7 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
144
148
keep_alive : true ,
145
149
max_buf_size : None ,
146
150
pipeline : false ,
151
+ sleep_on_errors : false ,
147
152
_marker : PhantomData ,
148
153
}
149
154
}
@@ -172,6 +177,18 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
172
177
self
173
178
}
174
179
180
+ /// Swallow connection accept errors. Instead of passing up IO errors when
181
+ /// the server is under heavy load the errors will be ignored. Some
182
+ /// connection accept errors (like "connection reset") can be ignored, some
183
+ /// (like "too many files open") may consume 100% CPU and a timout of 10ms
184
+ /// is used in that case.
185
+ ///
186
+ /// Default is false.
187
+ pub fn sleep_on_errors ( & mut self , enabled : bool ) -> & mut Self {
188
+ self . sleep_on_errors = enabled;
189
+ self
190
+ }
191
+
175
192
/// Bind the provided `addr` and return a server ready to handle
176
193
/// connections.
177
194
///
@@ -225,7 +242,7 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
225
242
Bd : Stream < Item =B , Error =:: Error > ,
226
243
{
227
244
let listener = TcpListener :: bind ( addr, & handle) ?;
228
- let mut incoming = AddrIncoming :: new ( listener) ?;
245
+ let mut incoming = AddrIncoming :: new ( listener, handle . clone ( ) , self . sleep_on_errors ) ?;
229
246
if self . keep_alive {
230
247
incoming. set_keepalive ( Some ( Duration :: from_secs ( 90 ) ) ) ;
231
248
}
@@ -248,6 +265,7 @@ impl<B: AsRef<[u8]> + 'static> Http<B> {
248
265
keep_alive : self . keep_alive ,
249
266
max_buf_size : self . max_buf_size ,
250
267
pipeline : self . pipeline ,
268
+ sleep_on_errors : self . sleep_on_errors ,
251
269
_marker : PhantomData ,
252
270
} ,
253
271
}
@@ -394,7 +412,7 @@ impl<S, B> Server<S, B>
394
412
395
413
let handle = reactor. handle ( ) ;
396
414
397
- let mut incoming = AddrIncoming :: new ( listener) ?;
415
+ let mut incoming = AddrIncoming :: new ( listener, handle . clone ( ) , protocol . sleep_on_errors ) ?;
398
416
399
417
if protocol. keep_alive {
400
418
incoming. set_keepalive ( Some ( Duration :: from_secs ( 90 ) ) ) ;
@@ -619,11 +637,14 @@ mod unnameable {
619
637
// ===== impl AddrIncoming =====
620
638
621
639
impl AddrIncoming {
622
- fn new ( listener : TcpListener ) -> io:: Result < AddrIncoming > {
640
+ fn new ( listener : TcpListener , handle : Handle , sleep_on_errors : bool ) -> io:: Result < AddrIncoming > {
623
641
Ok ( AddrIncoming {
624
642
addr : listener. local_addr ( ) ?,
625
643
keep_alive_timeout : None ,
626
644
listener : listener,
645
+ handle : handle,
646
+ sleep_on_errors : sleep_on_errors,
647
+ timeout : None ,
627
648
} )
628
649
}
629
650
@@ -643,6 +664,13 @@ impl Stream for AddrIncoming {
643
664
type Error = :: std:: io:: Error ;
644
665
645
666
fn poll ( & mut self ) -> Poll < Option < Self :: Item > , Self :: Error > {
667
+ if let Some ( ref mut to) = self . timeout {
668
+ match to. poll ( ) . expect ( "timeout never fails" ) {
669
+ Async :: Ready ( _) => { }
670
+ Async :: NotReady => return Ok ( Async :: NotReady ) ,
671
+ }
672
+ }
673
+ self . timeout = None ;
646
674
loop {
647
675
match self . listener . accept ( ) {
648
676
Ok ( ( socket, addr) ) => {
@@ -654,12 +682,41 @@ impl Stream for AddrIncoming {
654
682
return Ok ( Async :: Ready ( Some ( AddrStream :: new ( socket, addr) ) ) ) ;
655
683
} ,
656
684
Err ( ref e) if e. kind ( ) == io:: ErrorKind :: WouldBlock => return Ok ( Async :: NotReady ) ,
657
- Err ( e) => return Err ( e) ,
685
+ Err ( ref e) if connection_error ( e) => continue ,
686
+ Err ( e) => {
687
+ let delay = :: std:: time:: Duration :: from_millis ( 10 ) ;
688
+ debug ! ( "Accept error: {}. Sleeping {:?}..." ,
689
+ e, delay) ;
690
+ let mut timeout = Timeout :: new ( delay, & self . handle )
691
+ . expect ( "can always set a timeout" ) ;
692
+ let result = timeout. poll ( )
693
+ . expect ( "timeout never fails" ) ;
694
+ match result {
695
+ Async :: Ready ( ( ) ) => continue ,
696
+ Async :: NotReady => {
697
+ self . timeout = Some ( timeout) ;
698
+ return Ok ( Async :: NotReady ) ;
699
+ }
700
+ }
701
+ }
658
702
}
659
703
}
660
704
}
661
705
}
662
706
707
+ /// This function defines errors that are per-connection. Which basically
708
+ /// means that if we get this error from `accept()` system call it means
709
+ /// next connection might be ready to be accepted.
710
+ ///
711
+ /// All other errors will incur a timeout before next `accept()` is performed.
712
+ /// The timeout is useful to handle resource exhaustion errors like ENFILE
713
+ /// and EMFILE. Otherwise, could enter into tight loop.
714
+ fn connection_error ( e : & io:: Error ) -> bool {
715
+ e. kind ( ) == io:: ErrorKind :: ConnectionRefused ||
716
+ e. kind ( ) == io:: ErrorKind :: ConnectionAborted ||
717
+ e. kind ( ) == io:: ErrorKind :: ConnectionReset
718
+ }
719
+
663
720
mod addr_stream {
664
721
use std:: io:: { self , Read , Write } ;
665
722
use std:: net:: SocketAddr ;
0 commit comments