Skip to content

Commit bc78bd6

Browse files
authored
Merge branch 'staging' into fix/2188-configure_uvicorn_event_loop
2 parents 569d4be + 1b6c0e8 commit bc78bd6

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

bittensor/core/axon.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,6 @@ def run_in_thread(self):
142142
self.should_exit = True
143143
thread.join()
144144

145-
def _wrapper_run(self):
146-
"""
147-
A wrapper method for the :func:`run_in_thread` context manager. This method is used internally by the ``start`` method to initiate the server's execution in a separate thread.
148-
"""
149-
with self.run_in_thread():
150-
while not self.should_exit:
151-
time.sleep(1e-3)
152-
153145
def start(self):
154146
"""
155147
Starts the FastAPI server in a separate thread if it is not already running. This method sets up the server to handle HTTP requests concurrently, enabling the Axon server to efficiently manage incoming network requests.
@@ -158,7 +150,7 @@ def start(self):
158150
"""
159151
if not self.is_running:
160152
self.should_exit = False
161-
thread = threading.Thread(target=self._wrapper_run, daemon=True)
153+
thread = threading.Thread(target=self.run, daemon=True)
162154
thread.start()
163155
self.is_running = True
164156

tests/unit_tests/test_axon.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@
1717

1818

1919
import re
20+
import threading
2021
import time
2122
from dataclasses import dataclass
2223
from typing import Any, Optional, Tuple
2324
from unittest import IsolatedAsyncioTestCase
2425
from unittest.mock import AsyncMock, MagicMock, patch
2526

27+
import aiohttp
2628
import fastapi
2729
import netaddr
2830
import pydantic
2931
import pytest
32+
import uvicorn
3033
from fastapi.testclient import TestClient
3134
from starlette.requests import Request
3235

33-
from bittensor.core.axon import AxonMiddleware, Axon
36+
from bittensor.core.axon import Axon, AxonMiddleware, FastAPIThreadedServer
3437
from bittensor.core.errors import RunException
3538
from bittensor.core.settings import version_as_int
3639
from bittensor.core.stream import StreamingSynapse
@@ -785,3 +788,45 @@ async def forward_fn(synapse: streaming_synapse_cls):
785788
"computed_body_hash": "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a",
786789
},
787790
)
791+
792+
793+
@pytest.mark.asyncio
794+
async def test_threaded_fastapi():
795+
server_started = threading.Event()
796+
server_stopped = threading.Event()
797+
798+
async def lifespan(app):
799+
server_started.set()
800+
yield
801+
server_stopped.set()
802+
803+
app = fastapi.FastAPI(
804+
lifespan=lifespan,
805+
)
806+
app.get("/")(lambda: "Hello World")
807+
808+
server = FastAPIThreadedServer(
809+
uvicorn.Config(
810+
app,
811+
),
812+
)
813+
server.start()
814+
815+
server_started.wait()
816+
817+
assert server.is_running is True
818+
819+
async with aiohttp.ClientSession(
820+
base_url="http://127.0.0.1:8000",
821+
) as session:
822+
async with session.get("/") as response:
823+
assert await response.text() == '"Hello World"'
824+
825+
server.stop()
826+
827+
assert server.should_exit is True
828+
829+
server_stopped.wait()
830+
831+
with pytest.raises(aiohttp.ClientConnectorError):
832+
await session.get("/")

0 commit comments

Comments
 (0)