77from asgi_lifespan import LifespanManager
88from celery import Celery # type: ignore[import-untyped]
99from fastapi import FastAPI
10- from servicelib .async_utils import cancel_wait_task
10+ from servicelib .logging_utils import log_context
1111
1212from ...core .application import create_app
1313from ...core .settings import ApplicationSettings
14- from ...modules .celery import get_event_loop , set_event_loop
14+ from ...modules .celery import set_event_loop
1515from ...modules .celery .utils import (
1616 get_fastapi_app ,
1717 set_celery_worker ,
2121
2222_logger = logging .getLogger (__name__ )
2323
24- _LIFESPAN_TIMEOUT : Final [int ] = 10
25- _FASTAPI_STARTUP_TIMEOUT : Final [float ] = datetime .timedelta (minutes = 1 ).total_seconds ()
24+ _SHUTDOWN_TIMEOUT : Final [float ] = datetime . timedelta ( seconds = 10 ). total_seconds ()
25+ _STARTUP_TIMEOUT : Final [float ] = datetime .timedelta (minutes = 1 ).total_seconds ()
2626
2727
2828def on_worker_init (sender , ** _kwargs ) -> None :
@@ -35,11 +35,13 @@ def _init_fastapi(startup_complete_event: threading.Event) -> None:
3535
3636 fastapi_app = create_app (ApplicationSettings .create_from_envs ())
3737
38- async def lifespan (startup_complete_event : threading .Event ) -> None :
38+ async def lifespan (
39+ startup_complete_event : threading .Event , shutdown_event : asyncio .Event
40+ ) -> None :
3941 async with LifespanManager (
4042 fastapi_app ,
41- startup_timeout = _LIFESPAN_TIMEOUT ,
42- shutdown_timeout = _LIFESPAN_TIMEOUT ,
43+ startup_timeout = _STARTUP_TIMEOUT ,
44+ shutdown_timeout = _SHUTDOWN_TIMEOUT ,
4345 ):
4446 try :
4547 _logger .info ("fastapi APP started!" )
@@ -48,37 +50,27 @@ async def lifespan(startup_complete_event: threading.Event) -> None:
4850 except asyncio .CancelledError :
4951 _logger .warning ("Lifespan task cancelled" )
5052
51- lifespan_task = loop .create_task (lifespan (startup_complete_event ))
52- fastapi_app .state .lifespan_task = lifespan_task
5353 fastapi_app .state .shutdown_event = shutdown_event
5454 set_event_loop (fastapi_app , loop )
5555
5656 set_fastapi_app (sender .app , fastapi_app )
5757 set_celery_worker (sender .app , CeleryTaskQueueWorker (sender .app ))
58-
59- loop .run_forever ()
58+ loop .run_until_complete (lifespan (startup_complete_event , shutdown_event ))
6059
6160 thread = threading .Thread (
61+ group = None ,
6262 target = _init_fastapi ,
6363 name = "fastapi_app" ,
6464 args = (startup_complete_event ,),
65- daemon = True ,
6665 )
6766 thread .start ()
6867 # ensure the fastapi app is ready before going on
69- startup_complete_event .wait (_FASTAPI_STARTUP_TIMEOUT )
70-
71-
72- def on_worker_shutdown (sender , ** _kwargs ):
73- assert isinstance (sender .app , Celery )
68+ startup_complete_event .wait (_STARTUP_TIMEOUT * 1.1 )
7469
75- fastapi_app = get_fastapi_app (sender .app )
76- assert isinstance (fastapi_app , FastAPI )
77- event_loop = get_event_loop (fastapi_app )
7870
79- async def shutdown ():
71+ def on_worker_shutdown (sender , ** _kwargs ) -> None :
72+ with log_context (_logger , logging .INFO , "Worker Shuts-down" ):
73+ assert isinstance (sender .app , Celery )
74+ fastapi_app = get_fastapi_app (sender .app )
75+ assert isinstance (fastapi_app , FastAPI )
8076 fastapi_app .state .shutdown_event .set ()
81-
82- await cancel_wait_task (fastapi_app .state .lifespan_task , max_delay = 5 )
83-
84- asyncio .run_coroutine_threadsafe (shutdown (), event_loop )
0 commit comments