11import asyncio
22import logging
33import uuid
4+ import platform
45import os
56from functools import partial
6- from typing import Any , List , Optional , TYPE_CHECKING , Text , Union , Dict
7+ from typing import (
8+ Any ,
9+ Callable ,
10+ List ,
11+ Optional ,
12+ Text ,
13+ Tuple ,
14+ Union ,
15+ Dict ,
16+ )
717
818import rasa .core .utils
919from rasa .plugin import plugin_manager
2333from sanic import Sanic
2434from asyncio import AbstractEventLoop
2535
26- if TYPE_CHECKING :
27- from aiohttp import ClientSession
2836
2937logger = logging .getLogger () # get the root logger
3038
@@ -80,6 +88,14 @@ def _create_app_without_api(cors: Optional[Union[Text, List[Text]]] = None) -> S
8088 return app
8189
8290
91+ def _is_apple_silicon_system () -> bool :
92+ # check if the system is MacOS
93+ if platform .system ().lower () != "darwin" :
94+ return False
95+ # check for arm architecture, indicating apple silicon
96+ return platform .machine ().startswith ("arm" ) or os .uname ().machine .startswith ("arm" )
97+
98+
8399def configure_app (
84100 input_channels : Optional [List ["InputChannel" ]] = None ,
85101 cors : Optional [Union [Text , List [Text ], None ]] = None ,
@@ -99,6 +115,9 @@ def configure_app(
99115 syslog_port : Optional [int ] = None ,
100116 syslog_protocol : Optional [Text ] = None ,
101117 request_timeout : Optional [int ] = None ,
118+ server_listeners : Optional [List [Tuple [Callable , Text ]]] = None ,
119+ use_uvloop : Optional [bool ] = True ,
120+ keep_alive_timeout : int = constants .DEFAULT_KEEP_ALIVE_TIMEOUT ,
102121) -> Sanic :
103122 """Run the agent."""
104123 rasa .core .utils .configure_file_logging (
@@ -118,6 +137,14 @@ def configure_app(
118137 else :
119138 app = _create_app_without_api (cors )
120139
140+ app .config .KEEP_ALIVE_TIMEOUT = keep_alive_timeout
141+ if _is_apple_silicon_system () or not use_uvloop :
142+ app .config .USE_UVLOOP = False
143+ # some library still sets the loop to uvloop, even if disabled for sanic
144+ # using uvloop leads to breakingio errors, see
145+ # https://rasahq.atlassian.net/browse/ENG-667
146+ asyncio .set_event_loop_policy (None )
147+
121148 if input_channels :
122149 channels .channel .register (input_channels , app , route = route )
123150 else :
@@ -150,6 +177,10 @@ async def run_cmdline_io(running_app: Sanic) -> None:
150177
151178 app .add_task (run_cmdline_io )
152179
180+ if server_listeners :
181+ for (listener , event ) in server_listeners :
182+ app .register_listener (listener , event )
183+
153184 return app
154185
155186
@@ -179,6 +210,7 @@ def serve_application(
179210 syslog_port : Optional [int ] = None ,
180211 syslog_protocol : Optional [Text ] = None ,
181212 request_timeout : Optional [int ] = None ,
213+ server_listeners : Optional [List [Tuple [Callable , Text ]]] = None ,
182214) -> None :
183215 """Run the API entrypoint."""
184216 if not channel and not credentials :
@@ -204,6 +236,7 @@ def serve_application(
204236 syslog_port = syslog_port ,
205237 syslog_protocol = syslog_protocol ,
206238 request_timeout = request_timeout ,
239+ server_listeners = server_listeners ,
207240 )
208241
209242 ssl_context = server .create_ssl_context (
@@ -217,7 +250,7 @@ def serve_application(
217250 partial (load_agent_on_start , model_path , endpoints , remote_storage ),
218251 "before_server_start" ,
219252 )
220- app . register_listener ( create_connection_pools , "after_server_start" )
253+
221254 app .register_listener (close_resources , "after_server_stop" )
222255
223256 number_of_workers = rasa .core .utils .number_of_sanic_workers (
@@ -279,44 +312,3 @@ async def close_resources(app: Sanic, _: AbstractEventLoop) -> None:
279312 event_broker = current_agent .tracker_store .event_broker
280313 if event_broker :
281314 await event_broker .close ()
282-
283- action_endpoint = current_agent .action_endpoint
284- if action_endpoint :
285- await action_endpoint .session .close ()
286-
287- model_server = current_agent .model_server
288- if model_server :
289- await model_server .session .close ()
290-
291-
292- async def create_connection_pools (app : Sanic , _ : AbstractEventLoop ) -> None :
293- """Create connection pools for the agent's action server and model server."""
294- current_agent = getattr (app .ctx , "agent" , None )
295- if not current_agent :
296- logger .debug ("No agent found after server start." )
297- return None
298-
299- create_action_endpoint_connection_pool (current_agent )
300- create_model_server_connection_pool (current_agent )
301-
302- return None
303-
304-
305- def create_action_endpoint_connection_pool (agent : Agent ) -> Optional ["ClientSession" ]:
306- """Create a connection pool for the action endpoint."""
307- action_endpoint = agent .action_endpoint
308- if not action_endpoint :
309- logger .debug ("No action endpoint found after server start." )
310- return None
311-
312- return action_endpoint .session
313-
314-
315- def create_model_server_connection_pool (agent : Agent ) -> Optional ["ClientSession" ]:
316- """Create a connection pool for the model server."""
317- model_server = agent .model_server
318- if not model_server :
319- logger .debug ("No model server endpoint found after server start." )
320- return None
321-
322- return model_server .session
0 commit comments