You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Various issues were encountered trying to run and understand e2e tests:
- if uvicorn fails to start, an uncaught exception is emitted to stderr
- axon keeps spinning waiting for self.started, indefinitely
- exceptions are not propagated from threads
- there is no way to (simply) test from the outside whether an axon
started and/or runs
- axon creates a thread that only creates another thread, which seems
redundant
This patch addresses some of these issues, in FastAPIThreadedServer:
- add thread safe set/get_exception() to set/get exceptions
- run_in_thread() yields the created thread, so that the code using it
can check whether the thread is alive
- uvicorn.Server.startup() is wrapped to set a thread-safe flag using
self.set_started(True) to indicate startup succeeded
- run_in_thread() times out after one second to prevent infinite loop in
case self.get_started() never becomes True
- run_in_thread() raises an exception if it fails to start the thread
- _wrapper_run() tests whether the thread is still alive
and in class axon, the following are added:
- @Property axon.exception(), returning any exception
- axon.is_running(), returning True when the axon is operational
The seemingly redundant thread is left in until feedback is received on
the reasons for including it.
Copy file name to clipboardExpand all lines: bittensor/axon.py
+77-6Lines changed: 77 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -26,6 +26,7 @@
26
26
importinspect
27
27
importjson
28
28
importos
29
+
importsocket
29
30
importthreading
30
31
importtime
31
32
importtraceback
@@ -100,26 +101,72 @@ class FastAPIThreadedServer(uvicorn.Server):
100
101
should_exit: bool=False
101
102
is_running: bool=False
102
103
104
+
"""
105
+
Provide a channel to signal exceptions from the thread to our caller.
106
+
"""
107
+
_exception: Exception=None
108
+
_lock: threading.Lock=threading.Lock()
109
+
_thread: threading.Thread=None
110
+
_started: bool=False
111
+
112
+
defset_exception(self, ex):
113
+
withself._lock:
114
+
self._exception=ex
115
+
116
+
defget_exception(self):
117
+
withself._lock:
118
+
returnself._exception
119
+
120
+
defset_thread(self, thread):
121
+
withself._lock:
122
+
self._thread=thread
123
+
124
+
defget_thread(self):
125
+
withself._lock:
126
+
returnself._thread
127
+
128
+
defset_started(self, started):
129
+
withself._lock:
130
+
self._started=started
131
+
132
+
defget_started(self):
133
+
withself._lock:
134
+
returnself._started
135
+
103
136
definstall_signal_handlers(self):
104
137
"""
105
138
Overrides the default signal handlers provided by ``uvicorn.Server``. This method is essential to ensure that the signal handling in the threaded server does not interfere with the main application's flow, especially in a complex asynchronous environment like the Axon server.
Adds a thread-safe call to set a 'started' flag on the object.
145
+
"""
146
+
ret=awaitsuper().startup(sockets)
147
+
self.set_started(True)
148
+
returnret
149
+
109
150
@contextlib.contextmanager
110
151
defrun_in_thread(self):
111
152
"""
112
153
Manages the execution of the server in a separate thread, allowing the FastAPI application to run asynchronously without blocking the main thread of the Axon server. This method is a key component in enabling concurrent request handling in the Axon server.
113
154
114
155
Yields:
115
-
None: This method yields control back to the caller while the server is running in the background thread.
156
+
thread: a running thread
157
+
158
+
Raises:
159
+
Exception: in case the server did not start (as signalled by self.get_started())
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.
0 commit comments