I am building a WebRTC app using aiortc package.
In the app, the client connects to the server using this library and streams video.
My problem is shutting down the server. I have tried multiple options that I saw online but only got a new exception every time...
My code is based on this post
My server code:
import asyncio
import datetime
from asyncio import Event
from asyncio.base_futures import CancelledError
from aiohttp import web
from aiohttp.web_runner import AppRunner
import web_rtc
_event: Event
_site: web.TCPSite
app: web.Application
runner: AppRunner
loop: asyncio.AbstractEventLoop
async def start_server1(host, port):
global loop
loop = asyncio.get_running_loop()
global _event, _site, runner
# Source: https://newbedev.com/how-to-run-an-aiohttp-server-in-a-thread
runner = _get_app_runner()
await runner.setup()
_site = web.TCPSite(runner, host, port)
await _site.start()
# wait forever
_event = asyncio.Event()
await _event.wait()
def start_server(host, port):
try:
asyncio.run(start_server1(host, port))
except CancelledError:
print('Server is down')
def stop_server():
for task in asyncio.tasks.all_tasks(app._loop):
print(f'Task {task.cancel()}')
print('Set')
_event.set()
asyncio.run(do_close())
async def do_close():
print('App')
await app.shutdown()
for task in asyncio.all_tasks(loop):
print(f'- Task {task.cancel()}')
print('runner')
await runner.shutdown()
print('Site')
await _site.stop()
print('Loop')
await loop.shutdown_asyncgens()
loop.stop()
print(loop.is_running(), loop.is_closed())
# loop.close()
async def _main_page_response(_):
return web.Response(content_type='text/plain', text=f'Hello and welcome {datetime.datetime.now()}')
# region Private functions
def _get_app_runner() -> web.AppRunner:
global app
app = web.Application()
app.on_shutdown.append(_on_shutdown)
app.router.add_get("/", _main_page_response)
app.router.add_post("/offer", web_rtc.process_offer)
app._set_loop(asyncio.get_event_loop())
return web.AppRunner(app)
async def _on_shutdown(_):
print('SHUTTING DOWN APP')
await web_rtc.shutdown()
# endregion
My main method code that runs the server:
import threading
import server
# Another script I have that simply handles with the configuration file
from Code.CoreProduct import config
class StoppableThread(threading.Thread):
"""
Source: https://stackoverflow.com/a/325528/9977758
Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition.
"""
def __init__(self, *args, **kwargs):
super(StoppableThread, self).__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def main():
print('Reading configuration file')
cfg = config.get_config()
print('Initializing inference parameters')
print(f'Server address: http://{cfg.SERVER.HOST}:{cfg.SERVER.PORT}')
server_thread = StoppableThread(target=server.start_server, args=(cfg.SERVER.HOST, cfg.SERVER.PORT))
print('Starting the thread')
server_thread.start()
try:
# Wait until the shutdown key is pressed
while input('Press X to stop the server:\t') != 'X':
pass
finally: # Make sure we shutdown the server and stopping the thread.
server.stop_server()
server_thread.stop()
if __name__ == '__main__':
main()
The code starts the server on a new thread and waits for the user to press X.
The problem is the stop_server function in the server code, it keeps raising exceptions.
After I send a get-request to the server, the shutdown function raises RuntimeError: Timeout context manager should be used inside a task on the line with await _site.stop()