| 218 | raise DashAppLoadingError("threaded server failed to start") |
| 219 | |
| 220 | def stop(self): |
| 221 | # For FastAPI apps with uvicorn, use graceful shutdown |
| 222 | if self._app and hasattr(self._app, "_uvicorn_server"): |
| 223 | server = self._app._uvicorn_server # pylint: disable=protected-access |
| 224 | server.should_exit = True |
| 225 | self.thread.join(timeout=self.stop_timeout) # type: ignore[reportOptionalMemberAccess] |
| 226 | else: |
| 227 | # Fall back to killing threads for Flask/other backends |
| 228 | self.thread.kill() # type: ignore[reportOptionalMemberAccess] |
| 229 | self.thread.join() # type: ignore[reportOptionalMemberAccess] |
| 230 | wait.until_not(self.thread.is_alive, self.stop_timeout) # type: ignore[reportOptionalMemberAccess] |
| 231 | self._app = None |
| 232 | self.started = False |
| 233 | |
| 234 | |
| 235 | class MultiProcessRunner(BaseDashRunner): |