MagicStack / MagicStack/uvloop

Application hanging after KeyboardInterrupt

Abierto
#335 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Lenguaje dominante
Cython
Estrellas
11.9k
Forks
616
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

* **uvloop version**: 0.14.0
* **Python version**: 3.7.4
* **Platform**: Manjaro
* **Can you reproduce the bug with `PYTHONASYNCIODEBUG` in env?**: Yes
* **Does uvloop behave differently from vanilla asyncio? How?**: With vanilla, the application terminates gracefully upon reception of a keyboard interrupt. If I use `uvloop`, I get a runtime warning and the application hangs until I run a `kill -9` on the process id.

Snippet: `issue.py`
```
import asyncio
from asyncio import AbstractEventLoop
import os
from typing import Union, Type

import uvloop # type: ignore
from aiohttp import web
import signal

import aiologger

logger = aiologger.Logger.with_default_handlers()

async def handle_exception(loop: AbstractEventLoop, context):
# context["message"] will always be there; but context["exception"] may not
msg = context.get("exception", context["message"])
await logger.error(f"Caught exception: {msg}")
await logger.info("Shutting down...")
asyncio.create_task(shutdown(loop))

async def shutdown(loop: AbstractEventLoop, signal=None):
"""Cleanup tasks tied to the service's shutdown."""
if signal:
await logger.info(f"Received exit signal {signal.name}...")

tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]

[task.cancel() for task in tasks]

await logger.info(f"Cancelling {len(tasks)} outstanding tasks")
await asyncio.gather(*tasks, return_exceptions=True)
loop.stop()

async def start(
app: web.Application, host: str, port: Union[str, int]
) -> web.AppRunner:
"""Start the server"""
runner = web.AppRunner(app)
await runner.setup()
server = web.TCPSite(runner, host, int(port))
await server.start()
return runner

def main() -> None:
"""Entrypoint"""
host = os.environ.get("HOST", "localhost")
port = os.environ.get("PORT", 8000)
app = web.Application()
loop = asyncio.get_event_loop()
signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT)
for s in signals:
loop.add_signal_handler(
s, lambda s=s: asyncio.create_task(shutdown(loop, signal=s))
)
loop.set_exception_handler(handle_exception)
print(
f"======== Running on http://{host}:{port} ========\n" "(Press CTRL+C to quit)"
)
try:
runner = loop.run_until_complete(start(app, host, port))
loop.run_forever()
finally:
loop.run_until_complete(runner.cleanup())
loop.close()

if __name__ == "__main__":
uvloop.install()
main()

```

Run the file:
`python issue.py`

Then hit Ctrl+c on keyboard, output:
```
======== Running on http://0.0.0.0:8000 ========
(Press CTRL+C to quit)
^Cissue.py:70: RuntimeWarning: coroutine 'handle_exception' was never awaited
Coroutine created at (most recent call last)
File "issue.py", line 78, in
main()
File "issue.py", line 70, in main
loop.run_forever()
loop.run_forever()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
```
Which hangs until running `kill -9 `

If you comment out `uvloop.install()` and follow the same steps, the program terminates as expected. Output:
```
======== Running on http://0.0.0.0:8000 ========
(Press CTRL+C to quit)
^CReceived exit signal SIGINT...
Cancelling 0 outstanding tasks

```

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Empieza ejecutando issue.py con uvloop 0.14.0, Python 3.7.4 y PYTHONASYNCIODEBUG habilitado; después, compara su comportamiento con Ctrl+C con el de vanilla asyncio. Investiga el manejo de excepciones del bucle de eventos y la ruta de apagado por señal que se muestran en el fragmento. Se considera terminado cuando KeyboardInterrupt activa una limpieza ordenada sin la advertencia de una coroutine no esperada ni un proceso bloqueado.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
backend
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
38/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.