1
- use std:: future:: Future ;
2
- use std:: pin:: Pin ;
3
- use std:: sync:: atomic:: { AtomicBool , AtomicUsize , Ordering } ;
4
- use std:: sync:: Arc ;
5
- use std:: task:: { Context , Poll } ;
6
- use std:: time:: Duration ;
7
-
8
- use actix_rt:: time:: { sleep, Sleep } ;
9
- use actix_rt:: { spawn, Arbiter } ;
1
+ use std:: {
2
+ future:: Future ,
3
+ mem,
4
+ pin:: Pin ,
5
+ sync:: {
6
+ atomic:: { AtomicBool , AtomicUsize , Ordering } ,
7
+ Arc ,
8
+ } ,
9
+ task:: { Context , Poll } ,
10
+ time:: Duration ,
11
+ } ;
12
+
13
+ use actix_rt:: {
14
+ spawn,
15
+ time:: { sleep, Instant , Sleep } ,
16
+ Arbiter ,
17
+ } ;
10
18
use actix_utils:: counter:: Counter ;
11
19
use futures_core:: { future:: LocalBoxFuture , ready} ;
12
20
use log:: { error, info, trace} ;
13
- use tokio:: sync:: mpsc:: { unbounded_channel, UnboundedReceiver , UnboundedSender } ;
14
- use tokio:: sync:: oneshot;
21
+ use tokio:: sync:: {
22
+ mpsc:: { unbounded_channel, UnboundedReceiver , UnboundedSender } ,
23
+ oneshot,
24
+ } ;
15
25
16
26
use crate :: service:: { BoxedServerService , InternalServiceFactory } ;
17
27
use crate :: socket:: MioStream ;
@@ -132,7 +142,7 @@ pub(crate) struct ServerWorker {
132
142
conns : Counter ,
133
143
factories : Vec < Box < dyn InternalServiceFactory > > ,
134
144
state : WorkerState ,
135
- config : ServerWorkerConfig ,
145
+ shutdown_timeout : Duration ,
136
146
}
137
147
138
148
struct WorkerService {
@@ -211,12 +221,12 @@ impl ServerWorker {
211
221
let mut wrk = MAX_CONNS_COUNTER . with ( move |conns| ServerWorker {
212
222
rx,
213
223
rx2,
224
+ services : Default :: default ( ) ,
214
225
availability,
215
226
factories,
216
- config ,
217
- services : Vec :: new ( ) ,
227
+ state : Default :: default ( ) ,
228
+ shutdown_timeout : config . shutdown_timeout ,
218
229
conns : conns. clone ( ) ,
219
- state : WorkerState :: Unavailable ,
220
230
} ) ;
221
231
222
232
let fut = wrk
@@ -337,61 +347,69 @@ enum WorkerState {
337
347
Token ,
338
348
LocalBoxFuture < ' static , Result < Vec < ( Token , BoxedServerService ) > , ( ) > > ,
339
349
) ,
340
- Shutdown (
341
- Pin < Box < Sleep > > ,
342
- Pin < Box < Sleep > > ,
343
- Option < oneshot:: Sender < bool > > ,
344
- ) ,
350
+ // Shutdown keep states necessary for server shutdown:
351
+ // Sleep for interval check the shutdown progress.
352
+ // Instant for the start time of shutdown.
353
+ // Sender for send back the shutdown outcome(force/grace) to StopCommand caller.
354
+ Shutdown ( Pin < Box < Sleep > > , Instant , oneshot:: Sender < bool > ) ,
355
+ }
356
+
357
+ impl Default for WorkerState {
358
+ fn default ( ) -> Self {
359
+ Self :: Unavailable
360
+ }
345
361
}
346
362
347
363
impl Future for ServerWorker {
348
364
type Output = ( ) ;
349
365
350
366
fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
367
+ let this = self . as_mut ( ) . get_mut ( ) ;
368
+
351
369
// `StopWorker` message handler
352
370
if let Poll :: Ready ( Some ( StopCommand { graceful, result } ) ) =
353
- Pin :: new ( & mut self . rx2 ) . poll_recv ( cx)
371
+ Pin :: new ( & mut this . rx2 ) . poll_recv ( cx)
354
372
{
355
- self . availability . set ( false ) ;
373
+ this . availability . set ( false ) ;
356
374
let num = num_connections ( ) ;
357
375
if num == 0 {
358
376
info ! ( "Shutting down worker, 0 connections" ) ;
359
377
let _ = result. send ( true ) ;
360
378
return Poll :: Ready ( ( ) ) ;
361
379
} else if graceful {
362
- self . shutdown ( false ) ;
363
380
info ! ( "Graceful worker shutdown, {} connections" , num) ;
364
- self . state = WorkerState :: Shutdown (
365
- Box :: pin ( sleep ( Duration :: from_secs ( 1 ) ) ) ,
366
- Box :: pin ( sleep ( self . config . shutdown_timeout ) ) ,
367
- Some ( result ) ,
368
- ) ;
381
+ this . shutdown ( false ) ;
382
+
383
+ let timer = Box :: pin ( sleep ( Duration :: from_secs ( 1 ) ) ) ;
384
+ let start_from = Instant :: now ( ) ;
385
+ this . state = WorkerState :: Shutdown ( timer , start_from , result ) ;
369
386
} else {
370
387
info ! ( "Force shutdown worker, {} connections" , num) ;
371
- self . shutdown ( true ) ;
388
+ this. shutdown ( true ) ;
389
+
372
390
let _ = result. send ( false ) ;
373
391
return Poll :: Ready ( ( ) ) ;
374
392
}
375
393
}
376
394
377
- match self . state {
378
- WorkerState :: Unavailable => match self . check_readiness ( cx) {
395
+ match this . state {
396
+ WorkerState :: Unavailable => match this . check_readiness ( cx) {
379
397
Ok ( true ) => {
380
- self . state = WorkerState :: Available ;
381
- self . availability . set ( true ) ;
398
+ this . state = WorkerState :: Available ;
399
+ this . availability . set ( true ) ;
382
400
self . poll ( cx)
383
401
}
384
402
Ok ( false ) => Poll :: Pending ,
385
403
Err ( ( token, idx) ) => {
386
- self . restart_service ( token, idx) ;
404
+ this . restart_service ( token, idx) ;
387
405
self . poll ( cx)
388
406
}
389
407
} ,
390
408
WorkerState :: Restarting ( idx, token, ref mut fut) => {
391
409
let item = ready ! ( fut. as_mut( ) . poll( cx) ) . unwrap_or_else ( |_| {
392
410
panic ! (
393
411
"Can not restart {:?} service" ,
394
- self . factories[ idx] . name( token)
412
+ this . factories[ idx] . name( token)
395
413
)
396
414
} ) ;
397
415
@@ -403,60 +421,61 @@ impl Future for ServerWorker {
403
421
404
422
trace ! (
405
423
"Service {:?} has been restarted" ,
406
- self . factories[ idx] . name( token)
424
+ this . factories[ idx] . name( token)
407
425
) ;
408
426
409
- self . services [ token. 0 ] . created ( service) ;
410
- self . state = WorkerState :: Unavailable ;
427
+ this . services [ token. 0 ] . created ( service) ;
428
+ this . state = WorkerState :: Unavailable ;
411
429
412
430
self . poll ( cx)
413
431
}
414
- WorkerState :: Shutdown ( ref mut t1, ref mut t2, ref mut tx) => {
415
- let num = num_connections ( ) ;
416
- if num == 0 {
417
- let _ = tx. take ( ) . unwrap ( ) . send ( true ) ;
432
+ WorkerState :: Shutdown ( ref mut timer, ref start_from, _) => {
433
+ // Wait for 1 second.
434
+ ready ! ( timer. as_mut( ) . poll( cx) ) ;
435
+
436
+ if num_connections ( ) == 0 {
437
+ // Graceful shutdown.
438
+ if let WorkerState :: Shutdown ( _, _, sender) = mem:: take ( & mut this. state ) {
439
+ let _ = sender. send ( true ) ;
440
+ }
418
441
Arbiter :: current ( ) . stop ( ) ;
419
- return Poll :: Ready ( ( ) ) ;
420
- }
421
-
422
- // check graceful timeout
423
- if Pin :: new ( t2) . poll ( cx) . is_ready ( ) {
424
- let _ = tx. take ( ) . unwrap ( ) . send ( false ) ;
425
- self . shutdown ( true ) ;
442
+ Poll :: Ready ( ( ) )
443
+ } else if start_from. elapsed ( ) >= this. shutdown_timeout {
444
+ // Timeout forceful shutdown.
445
+ if let WorkerState :: Shutdown ( _, _, sender) = mem:: take ( & mut this. state ) {
446
+ let _ = sender. send ( false ) ;
447
+ }
426
448
Arbiter :: current ( ) . stop ( ) ;
427
- return Poll :: Ready ( ( ) ) ;
428
- }
429
-
430
- // sleep for 1 second and then check again
431
- if t1. as_mut ( ) . poll ( cx) . is_ready ( ) {
432
- * t1 = Box :: pin ( sleep ( Duration :: from_secs ( 1 ) ) ) ;
433
- let _ = t1. as_mut ( ) . poll ( cx) ;
449
+ Poll :: Ready ( ( ) )
450
+ } else {
451
+ // Reset timer and wait for 1 second.
452
+ let time = Instant :: now ( ) + Duration :: from_secs ( 1 ) ;
453
+ timer. as_mut ( ) . reset ( time) ;
454
+ timer. as_mut ( ) . poll ( cx)
434
455
}
435
-
436
- Poll :: Pending
437
456
}
438
457
// actively poll stream and handle worker command
439
458
WorkerState :: Available => loop {
440
- match self . check_readiness ( cx) {
459
+ match this . check_readiness ( cx) {
441
460
Ok ( true ) => { }
442
461
Ok ( false ) => {
443
462
trace ! ( "Worker is unavailable" ) ;
444
- self . availability . set ( false ) ;
445
- self . state = WorkerState :: Unavailable ;
463
+ this . availability . set ( false ) ;
464
+ this . state = WorkerState :: Unavailable ;
446
465
return self . poll ( cx) ;
447
466
}
448
467
Err ( ( token, idx) ) => {
449
- self . restart_service ( token, idx) ;
450
- self . availability . set ( false ) ;
468
+ this . restart_service ( token, idx) ;
469
+ this . availability . set ( false ) ;
451
470
return self . poll ( cx) ;
452
471
}
453
472
}
454
473
455
- match ready ! ( Pin :: new( & mut self . rx) . poll_recv( cx) ) {
474
+ match ready ! ( Pin :: new( & mut this . rx) . poll_recv( cx) ) {
456
475
// handle incoming io stream
457
476
Some ( WorkerCommand ( msg) ) => {
458
- let guard = self . conns . get ( ) ;
459
- let _ = self . services [ msg. token . 0 ] . service . call ( ( guard, msg. io ) ) ;
477
+ let guard = this . conns . get ( ) ;
478
+ let _ = this . services [ msg. token . 0 ] . service . call ( ( guard, msg. io ) ) ;
460
479
}
461
480
None => return Poll :: Ready ( ( ) ) ,
462
481
} ;
0 commit comments