Repository: litestar-org/litestar

Issue:
Bug: Issue with reload
**Describe the bug**
When I start my app using starlite run -r I get the following error

INFO:     Will watch for changes in these directories: ['/Users/alc/starlite-apps/starlite_test']
ERROR:    [Errno 48] Address already in use

If I stop that and run it without -r it works, so I guess my port is not blocked

**To Reproduce**
Save this as `app.py`

```python
from starlite import get, Starlite

@get('/')
def route() -> str:
    return 'Hello'

app = Starlite([route])
```

**Additional context**
@provinzkraut in discord help suggested a workaround using ` uvicorn <app file>:<application object> --reload` and also linked https://github.com/encode/uvicorn/issues/1045




Discussion:
ok, assigning this to @provinzkraut for now - he will check it once he feels bette (covid got him). 

Resolving patch:
diff --git a/starlite/cli/commands/core.py b/starlite/cli/commands/core.py
--- a/starlite/cli/commands/core.py
+++ b/starlite/cli/commands/core.py
@@ -2,17 +2,31 @@
 
 import inspect
 import multiprocessing
+import subprocess
+from typing import Any
 
 import click
 from click import command, option
 from rich.tree import Tree
 
 from starlite import Starlite
-from starlite.cli.utils import StarliteCLIException, StarliteEnv, console, show_app_info
+from starlite.cli.utils import StarliteEnv, console, show_app_info
 from starlite.routes import HTTPRoute, WebSocketRoute
 from starlite.utils.helpers import unwrap_partial
 
 
+def _convert_uvicorn_args(args: dict[str, Any]) -> list[str]:
+    process_args = []
+    for arg, value in args.items():
+        if isinstance(value, bool):
+            if value:
+                process_args.append(f"--{arg}")
+        else:
+            process_args.append(f"--{arg}={value}")
+
+    return process_args
+
+
 @command(name="info")
 def info_command(app: Starlite) -> None:
     """Show information about the detected Starlite app."""
@@ -51,11 +65,6 @@ def run_command(
     instance.
     """
 
-    try:
-        import uvicorn
-    except ImportError:
-        raise StarliteCLIException("Uvicorn needs to be installed to run an app")  # pylint: disable=W0707
-
     if debug or env.debug:
         app.debug = True
 
@@ -63,14 +72,18 @@ def run_command(
 
     console.rule("[yellow]Starting server process", align="left")
 
-    uvicorn.run(
-        env.app_path,
-        reload=env.reload or reload,
-        host=env.host or host,
-        port=env.port or port,
-        workers=env.web_concurrency or web_concurrency,
-        factory=env.is_app_factory,
-    )
+    # invoke uvicorn in a subprocess to be able to use the --reload flag. see
+    # https://github.com/starlite-api/starlite/issues/1191 and https://github.com/encode/uvicorn/issues/1045
+
+    process_args = {
+        "reload": env.reload or reload,
+        "host": env.host or host,
+        "port": env.port or port,
+        "workers": env.web_concurrency or web_concurrency,
+        "factory": env.is_app_factory,
+    }
+
+    subprocess.run(["uvicorn", env.app_path, *_convert_uvicorn_args(process_args)], check=True)
 
 
 @command(name="routes")


Test patch:
diff --git a/tests/cli/test_run_command.py b/tests/cli/test_run_command.py
--- a/tests/cli/test_run_command.py
+++ b/tests/cli/test_run_command.py
@@ -17,6 +17,11 @@
 from tests.cli.conftest import CreateAppFileFixture
 
 
+@pytest.fixture()
+def mock_subprocess_run(mocker: MockerFixture) -> MagicMock:
+    return mocker.patch("starlite.cli.commands.core.subprocess.run")
+
+
 @pytest.mark.parametrize("set_in_env", [True, False])
 @pytest.mark.parametrize("custom_app_file", [Path("my_app.py"), None])
 @pytest.mark.parametrize("host", ["0.0.0.0", None])
@@ -27,7 +32,6 @@ def test_run_command(
     mocker: MockerFixture,
     runner: CliRunner,
     monkeypatch: MonkeyPatch,
-    mock_uvicorn_run: MagicMock,
     reload: Optional[bool],
     port: Optional[int],
     host: Optional[str],
@@ -35,6 +39,7 @@ def test_run_command(
     custom_app_file: Optional[Path],
     create_app_file: CreateAppFileFixture,
     set_in_env: bool,
+    mock_subprocess_run: MagicMock,
 ) -> None:
     mock_show_app_info = mocker.patch("starlite.cli.commands.core.show_app_info")
 
@@ -82,9 +87,14 @@ def test_run_command(
     assert result.exception is None
     assert result.exit_code == 0
 
-    mock_uvicorn_run.assert_called_once_with(
-        f"{path.stem}:app", reload=reload, port=port, host=host, factory=False, workers=web_concurrency
-    )
+    expected_args = ["uvicorn", f"{path.stem}:app", f"--host={host}", f"--port={port}"]
+    if reload:
+        expected_args.append("--reload")
+    if web_concurrency:
+        expected_args.append(f"--workers={web_concurrency}")
+
+    mock_subprocess_run.assert_called_once()
+    assert sorted(mock_subprocess_run.call_args_list[0].args[0]) == sorted(expected_args)
     mock_show_app_info.assert_called_once()
 
 
@@ -99,7 +109,7 @@ def test_run_command(
 )
 def test_run_command_with_autodiscover_app_factory(
     runner: CliRunner,
-    mock_uvicorn_run: MagicMock,
+    mock_subprocess_run: MagicMock,
     file_name: str,
     file_content: str,
     factory_name: str,
@@ -113,14 +123,21 @@ def test_run_command_with_autodiscover_app_factory(
     assert result.exception is None
     assert result.exit_code == 0
 
-    mock_uvicorn_run.assert_called_once_with(
-        f"{path.stem}:{factory_name}", reload=False, port=8000, host="127.0.0.1", factory=True, workers=1
-    )
+    expected_args = [
+        "uvicorn",
+        f"{path.stem}:{factory_name}",
+        "--host=127.0.0.1",
+        "--port=8000",
+        "--factory",
+        "--workers=1",
+    ]
+    mock_subprocess_run.assert_called_once()
+    assert sorted(mock_subprocess_run.call_args_list[0].args[0]) == sorted(expected_args)
 
 
 def test_run_command_with_app_factory(
     runner: CliRunner,
-    mock_uvicorn_run: MagicMock,
+    mock_subprocess_run: MagicMock,
     create_app_file: CreateAppFileFixture,
 ) -> None:
     path = create_app_file("_create_app_with_path.py", content=CREATE_APP_FILE_CONTENT)
@@ -130,12 +147,24 @@ def test_run_command_with_app_factory(
     assert result.exception is None
     assert result.exit_code == 0
 
-    mock_uvicorn_run.assert_called_once_with(
-        f"{app_path}", reload=False, port=8000, host="127.0.0.1", factory=True, workers=1
-    )
+    expected_args = [
+        "uvicorn",
+        str(app_path),
+        "--host=127.0.0.1",
+        "--port=8000",
+        "--factory",
+        "--workers=1",
+    ]
+    mock_subprocess_run.assert_called_once()
+    assert sorted(mock_subprocess_run.call_args_list[0].args[0]) == sorted(expected_args)
 
 
-def test_run_command_force_debug(app_file: Path, mocker: MockerFixture, runner: CliRunner) -> None:
+def test_run_command_force_debug(
+    app_file: Path,
+    mocker: MockerFixture,
+    runner: CliRunner,
+    mock_subprocess_run: MagicMock,
+) -> None:
     mock_app = MagicMock()
     mocker.patch(
         "starlite.cli.utils._autodiscover_app",