Assistant: 
User: User: ```
import asyncio
import argparse

import uvicorn
from loguru import logger

import config as cfg
from loader import app
from api import account, auth, recruiter, dashboard
from api.routers import protected, unprotected
from utils.init_db import init_db
from utils.fake_data import filling_fake_data


def run_server():
    app.include_router(unprotected, prefix="/api")
    app.include_router(protected, prefix="/api")
    uvicorn.run(app, host=cfg.API_HOST, port=cfg.API_PORT)


async def main():
    parser = argparse.ArgumentParser(description="Backend VisionHire")
    parser.add_argument('--action', type=str, choices=['init_db', 'filling_fake_data'], help='Action to perform')

    args = parser.parse_args()

    if args.action == 'init_db':
        await init_db()
    elif args.action == 'filling_fake_data':
        await filling_fake_data()
    else:
        run_server()


if __name__ == "__main__":
    try:
        import uvloop
        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
        logger.info("uvloop installed")
    except Exception:
        logger.warning("uvloop not installed")

    asyncio.run(main())
```


python app.py
2024-10-06 15:40:13.139 | INFO     | __main__:<module>:39 - uvloop installed
Traceback (most recent call last):
  File "/home/dimflix/VisionHire/backend/src/app.py", line 43, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
  File "/home/dimflix/VisionHire/backend/src/app.py", line 32, in main
    run_server()
  File "/home/dimflix/VisionHire/backend/src/app.py", line 18, in run_server
    uvicorn.run(app, host=cfg.API_HOST, port=cfg.API_PORT)
  File "/home/dimflix/.cache/pypoetry/virtualenvs/backend-N-Bw4l0p-py3.12/lib/python3.12/site-packages/uvicorn/main.py", line 577, in run
    server.run()
  File "/home/dimflix/.cache/pypoetry/virtualenvs/backend-N-Bw4l0p-py3.12/lib/python3.12/site-packages/uvicorn/server.py", line 65, in run
    return asyncio.run(self.serve(sockets=sockets))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 190, in run
    raise RuntimeError(
RuntimeError: asyncio.run() cannot be called from a running event loop
sys:1: RuntimeWarning: coroutine 'Server.serve' was never awaited
Assistant: The error you're encountering is due to the fact that `asyncio.run()` cannot be used when an event loop is already running, which happens when you use `uvloop` with `uvicorn` to run async functions within an already existing event loop.

Here’s a solution to this problem: you should change how you start the server. Instead of using `asyncio.run()`, you can use a different approach to execute your async functions when a loop is already running.

Here's how you can modify the `run_server` function to avoid this issue:

```python
import asyncio
import argparse

import uvicorn
from loguru import logger

import config as cfg
from loader import app
from api import account, auth, recruiter, dashboard
from api.routers import protected, unprotected
from utils.init_db import init_db
from utils.fake_data import filling_fake_data


def run_server():
    app.include_router(unprotected, prefix="/api")
    app.include_router(protected, prefix="/api")
    uvicorn.run(app, host=cfg.API_HOST, port=cfg.API_PORT)


async def main():
    parser = argparse.ArgumentParser(description="Backend VisionHire")
    parser.add_argument('--action', type=str, choices=['init_db', 'filling_fake_data'], help='Action to perform')

    args = parser.parse_args()

    if args.action == 'init_db':
        await init_db()
    elif args.action == 'filling_fake_data':
        await filling_fake_data()
    else:
        # Wrapping run_server() call inside a Future to run it on the running event loop.
        loop = asyncio.get_running_loop()
        future = loop.run_in_executor(None, run_server)
        await future

if __name__ == "__main__":
    try:
        import uvloop
        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
        logger.info("uvloop installed")
    except Exception:
        logger.warning("uvloop not installed")

    # Remove asyncio.run and directly use uvloop and asyncio
    asyncio.run(main())
```

In this revised code, the `run_server` function is moved into a separate thread using `loop.run_in_executor()`, which is safe to call in an already running event loop. This avoids the conflict of trying to run a new event loop using `asyncio.run` inside a running loop.
User: а как завершать скрипт
он на ctrl + c завершается не с первого раза а с 3
Assistant: Чтобы ваш скрипт корректно завершался при нажатии Ctrl+C (SIGINT), нужно позаботиться о том, чтобы все асинхронные задачи были правильно остановлены и завершены. Вы можете улучшить обработку сигнала остановки, добавив специальную сигнальную обработку для корректного завершения сервера Uvicorn и самого приложения.

Вот пример, как вы можете это сделать:

```python
import asyncio
import argparse
import signal

import uvicorn
from loguru import logger

import config as cfg
from loader import app
from api import account, auth, recruiter, dashboard
from api.routers import protected, unprotected
from utils.init_db import init_db
from utils.fake_data import filling_fake_data


def run_server():
    app.include_router(unprotected, prefix="/api")
    app.include_router(protected, prefix="/api")
    uvicorn.run(app, host=cfg.API_HOST, port=cfg.API_PORT)


async def main():
    parser = argparse.ArgumentParser(description="Backend VisionHire")
    parser.add_argument('--action', type=str, choices=['init_db', 'filling_fake_data'], help='Action to perform')

    args = parser.parse_args()

    if args.action == 'init_db':
        await init_db()
    elif args.action == 'filling_fake_data':
        await filling_fake_data()
    else:
        loop = asyncio.get_running_loop()

        # Create a future to run the server, which allows handling signal
        server_future = loop.run_in_executor(None, run_server)

        # Setup signal handler for graceful shutdown
        for signame in {'SIGINT', 'SIGTERM'}:
            loop.add_signal_handler(
                getattr(signal, signame),
                lambda: asyncio.create_task(shutdown(loop, server_future))
            )

        await server_future

async def shutdown(loop, server_future):
    logger.info("Shutting down...")
    server_future.cancel()

    # Give time to shutdown tasks properly
    await asyncio.sleep(1)

    loop.stop()

if __name__ == "__main__":
    try:
        import uvloop
        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
        logger.info("uvloop installed")
    except Exception:
        logger.warning("uvloop not installed")

    asyncio.run(main())
```

### Разбор кода:
- **Сигнальная обработка**: Мы добавляем обработчики сигналов `SIGINT` и `SIGTERM` для корректного завершения сервера. Это позволяет убедиться, что сервер завершится корректно при нажатии Ctrl+C.
- **`shutdown` функция**: Создаётся задача, которая отменяет выполнение будущей задачи (`server_future`) и останавливает цикл событий после небольшой задержки (для корректного завершения текущих задач).
- **Завершение сервера**: Использование `server_future.cancel()` позволяет прекратить выполнить задачу в executor.

Теперь ваш скрипт должен корректно завершаться после первого нажатия Ctrl+C.
User: давай по другому
он плохо завершает
Assistant:
Assistant: