@@ -424,6 +424,11 @@ async def serve(self, sock=None):
424
424
425
425
426
426
class ServerWithCallback (uvicorn .Server ):
427
+ def __init__ (self , config ):
428
+ super ().__init__ (config )
429
+ self .servers = [] # Initialize servers list
430
+ self .should_exit = False
431
+
427
432
def install_signal_handlers (self ):
428
433
def handle_exit (signum , frame ):
429
434
self .should_exit = True
@@ -436,207 +441,50 @@ async def startup(self, sockets=None):
436
441
if self .should_exit :
437
442
return
438
443
439
- if sockets is not None :
440
- try :
441
- await super (). startup ( sockets = sockets )
442
- logger . info ( "Using uvicorn's built-in Server implementation" )
443
- except Exception as e :
444
- logger .error (f"Error during server startup : { str ( e )} " )
445
- logger . debug ( f"Server startup error details: { traceback . format_exc () } " )
446
- self . servers = []
444
+ try :
445
+ await super (). startup ( sockets = sockets )
446
+ logger . info ( "Using uvicorn's built-in Server implementation" )
447
+ except Exception as e :
448
+ logger . error ( f"Error during server startup: { str ( e ) } " )
449
+ logger .debug (f"Server startup error details : { traceback . format_exc ( )} " )
450
+ self . servers = []
451
+ if sockets :
447
452
for socket in sockets :
448
453
server = SimpleTCPServer (config = self .config )
449
454
server .server = self
450
455
await server .start ()
451
456
self .servers .append (server )
452
- else :
453
- try :
454
- await super ().startup (sockets = None )
455
- logger .info ("Using uvicorn's built-in Server implementation" )
456
- except Exception as e :
457
- logger .error (f"Error during server startup: { str (e )} " )
458
- logger .debug (f"Server startup error details: { traceback .format_exc ()} " )
457
+ else :
459
458
server = SimpleTCPServer (config = self .config )
460
459
server .server = self
461
460
await server .start ()
462
- self .servers = [server ]
463
-
464
- if self .lifespan is not None :
465
- try :
466
- await self .lifespan .startup ()
467
- except Exception as e :
468
- logger .error (f"Error during lifespan startup: { str (e )} " )
469
- logger .debug (f"Lifespan startup error details: { traceback .format_exc ()} " )
470
- self .lifespan = NoopLifespan (self .config .app )
471
- logger .warning ("Replaced failed lifespan with NoopLifespan" )
472
-
473
- async def main_loop (self ):
474
- try :
475
- while not self .should_exit :
476
- await asyncio .sleep (0.05 )
477
-
478
- if self .should_exit :
479
- logger .debug ("Shutdown signal detected in main_loop" )
480
- break
481
- except Exception as e :
482
- logger .error (f"Error in main loop: { str (e )} " )
483
- logger .debug (f"Main loop error details: { traceback .format_exc ()} " )
484
- self .should_exit = True
485
-
486
- logger .debug ("Exiting main_loop" )
461
+ self .servers .append (server )
487
462
488
463
async def shutdown (self , sockets = None ):
489
464
logger .debug ("Starting server shutdown process" )
490
465
491
- if self .servers :
492
- for server in self .servers :
493
- try :
494
- server .close ()
495
- await server .wait_closed ()
496
- logger .debug ("Server closed successfully" )
497
- except Exception as e :
498
- logger .error (f"Error closing server: { str (e )} " )
499
- logger .debug (f"Server close error details: { traceback .format_exc ()} " )
466
+ # First shutdown any SimpleTCPServer instances
467
+ for server in self .servers :
468
+ try :
469
+ await server .shutdown ()
470
+ logger .debug ("SimpleTCPServer shutdown completed" )
471
+ except Exception as e :
472
+ logger .error (f"Error shutting down SimpleTCPServer: { str (e )} " )
500
473
474
+ # Clear servers list
475
+ self .servers = []
476
+
477
+ # Shutdown lifespan
501
478
if self .lifespan is not None :
502
479
try :
503
480
await self .lifespan .shutdown ()
504
481
logger .debug ("Lifespan shutdown completed" )
505
482
except Exception as e :
506
483
logger .error (f"Error during lifespan shutdown: { str (e )} " )
507
- logger .debug (f"Lifespan shutdown error details: { traceback .format_exc ()} " )
508
484
509
- self .servers = []
510
485
self .lifespan = None
511
486
512
487
logger .debug ("Server shutdown process completed" )
513
-
514
- async def serve (self , sockets = None ):
515
- self .config .setup_event_loop ()
516
-
517
- self .lifespan = None
518
-
519
- self ._initialize_lifespan ()
520
-
521
- try :
522
- await self .startup (sockets = sockets )
523
-
524
- if hasattr (self , 'on_startup_callback' ) and callable (self .on_startup_callback ):
525
- self .on_startup_callback ()
526
-
527
- await self .main_loop ()
528
- await self .shutdown ()
529
- except Exception as e :
530
- logger .error (f"Error during server operation: { str (e )} " )
531
- logger .debug (f"Server error details: { traceback .format_exc ()} " )
532
- raise
533
-
534
- def _initialize_lifespan (self ):
535
- try :
536
- from uvicorn .lifespan .on import LifespanOn
537
-
538
- try :
539
- self .lifespan = LifespanOn (config = self .config )
540
- logger .info ("Using LifespanOn from uvicorn.lifespan.on with config parameter" )
541
- return
542
- except TypeError :
543
- pass
544
-
545
- try :
546
- self .lifespan = LifespanOn (self .config .app )
547
- logger .info ("Using LifespanOn from uvicorn.lifespan.on with app parameter" )
548
- return
549
- except TypeError :
550
- pass
551
-
552
- try :
553
- lifespan_on = self .config .lifespan_on if hasattr (self .config , "lifespan_on" ) else "auto"
554
- self .lifespan = LifespanOn (self .config .app , lifespan_on )
555
- logger .info ("Using LifespanOn from uvicorn.lifespan.on with app and lifespan_on parameters" )
556
- return
557
- except TypeError :
558
- pass
559
-
560
- except (ImportError , AttributeError ):
561
- logger .debug ("Could not import LifespanOn from uvicorn.lifespan.on" )
562
-
563
- try :
564
- from uvicorn .lifespan .lifespan import Lifespan
565
-
566
- try :
567
- self .lifespan = Lifespan (self .config .app )
568
- logger .info ("Using Lifespan from uvicorn.lifespan.lifespan with app parameter" )
569
- return
570
- except TypeError :
571
- pass
572
-
573
- try :
574
- self .lifespan = Lifespan (self .config .app , "auto" )
575
- logger .info ("Using Lifespan from uvicorn.lifespan.lifespan with app and lifespan_on parameters" )
576
- return
577
- except TypeError :
578
- pass
579
-
580
- try :
581
- self .lifespan = Lifespan (self .config .app , "auto" , logger )
582
- logger .info ("Using Lifespan from uvicorn.lifespan.lifespan with app, lifespan_on, and logger parameters" )
583
- return
584
- except TypeError :
585
- pass
586
-
587
- except (ImportError , AttributeError ):
588
- logger .debug ("Could not import Lifespan from uvicorn.lifespan.lifespan" )
589
-
590
- try :
591
- from uvicorn .lifespan import Lifespan
592
-
593
- try :
594
- self .lifespan = Lifespan (self .config .app )
595
- logger .info ("Using Lifespan from uvicorn.lifespan with app parameter" )
596
- return
597
- except TypeError :
598
- pass
599
-
600
- try :
601
- self .lifespan = Lifespan (self .config .app , "auto" )
602
- logger .info ("Using Lifespan from uvicorn.lifespan with app and lifespan_on parameters" )
603
- return
604
- except TypeError :
605
- pass
606
-
607
- try :
608
- self .lifespan = Lifespan (self .config .app , "auto" , logger )
609
- logger .info ("Using Lifespan from uvicorn.lifespan with app, lifespan_on, and logger parameters" )
610
- return
611
- except TypeError :
612
- pass
613
-
614
- except (ImportError , AttributeError ):
615
- logger .debug ("Could not import Lifespan from uvicorn.lifespan" )
616
-
617
- try :
618
- from uvicorn .lifespan .state import LifespanState
619
-
620
- try :
621
- self .lifespan = LifespanState (self .config .app )
622
- logger .info ("Using LifespanState from uvicorn.lifespan.state with app parameter" )
623
- return
624
- except TypeError :
625
- pass
626
-
627
- try :
628
- self .lifespan = LifespanState (self .config .app , logger = logger )
629
- logger .info ("Using LifespanState from uvicorn.lifespan.state with app and logger parameters" )
630
- return
631
- except TypeError :
632
- pass
633
-
634
- except (ImportError , AttributeError ):
635
- logger .debug ("Could not import LifespanState from uvicorn.lifespan.state" )
636
-
637
- self .lifespan = NoopLifespan (self .config .app )
638
- logger .warning ("Using NoopLifespan - server may not handle startup/shutdown events properly" )
639
-
640
488
641
489
def start_server (use_ngrok : bool = None , port : int = None , ngrok_auth_token : Optional [str ] = None ):
642
490
try :
@@ -1017,7 +865,7 @@ async def on_startup_async():
1017
865
logger .warning ("Falling back to direct SimpleTCPServer implementation" )
1018
866
1019
867
1020
- direct_server = SimpleTCPServer (config )
868
+ direct_server = SimpleTCPServer (config = self . config )
1021
869
1022
870
1023
871
asyncio .run (direct_server .serve ())
@@ -1062,7 +910,7 @@ async def on_startup_async():
1062
910
logger .warning ("Falling back to direct SimpleTCPServer implementation" )
1063
911
1064
912
1065
- direct_server = SimpleTCPServer (config )
913
+ direct_server = SimpleTCPServer (config = self . config )
1066
914
1067
915
1068
916
loop .run_until_complete (direct_server .serve ())
@@ -1161,7 +1009,7 @@ async def on_startup_async():
1161
1009
logger .warning ("Falling back to direct SimpleTCPServer implementation" )
1162
1010
1163
1011
1164
- direct_server = SimpleTCPServer (config )
1012
+ direct_server = SimpleTCPServer (config = self . config )
1165
1013
1166
1014
1167
1015
asyncio .run (direct_server .serve ())
@@ -1206,7 +1054,7 @@ async def on_startup_async():
1206
1054
logger .warning ("Falling back to direct SimpleTCPServer implementation" )
1207
1055
1208
1056
1209
- direct_server = SimpleTCPServer (config )
1057
+ direct_server = SimpleTCPServer (config = self . config )
1210
1058
1211
1059
1212
1060
loop .run_until_complete (direct_server .serve ())
0 commit comments