Pass Error status in /dev/reload stream (#8106)

* get error message

* Support multiple clients

* add changeset

* add changeset

* add changeset

* Display in UI

* console.error the python traceback

* lint

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
Freddy Boulton 2024-05-01 18:21:54 -04:00 committed by GitHub
parent 68dcae512c
commit d0a759f3df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 41 additions and 13 deletions

View File

@ -0,0 +1,6 @@
---
"@gradio/app": patch
"gradio": patch
---
feat:Pass Error status in /dev/reload stream

View File

@ -137,15 +137,12 @@ def start_server(
)
reloader = None
if GRADIO_WATCH_DIRS:
change_event = threading.Event()
app.change_event = change_event
reloader = SourceFileReloader(
app=app,
watch_dirs=GRADIO_WATCH_DIRS,
watch_module_name=GRADIO_WATCH_MODULE_NAME,
demo_name=GRADIO_WATCH_DEMO_NAME,
stop_event=threading.Event(),
change_event=change_event,
demo_file=GRADIO_WATCH_DEMO_PATH,
)
server = Server(config=config, reloader=reloader)

View File

@ -19,7 +19,6 @@ import mimetypes
import os
import posixpath
import secrets
import threading
import time
import traceback
from pathlib import Path
@ -31,6 +30,7 @@ from typing import (
Callable,
Dict,
List,
Literal,
Optional,
Type,
Union,
@ -173,7 +173,9 @@ class App(FastAPI):
self.queue_token = secrets.token_urlsafe(32)
self.startup_events_triggered = False
self.uploaded_file_dir = get_upload_folder()
self.change_event: None | threading.Event = None
self.change_count: int = 0
self.change_type: Literal["reload", "error"] | None = None
self.reload_error_message: str | None = None
self._asyncio_tasks: list[asyncio.Task] = []
self.auth_dependency = auth_dependency
self.api_info = None
@ -284,14 +286,20 @@ class App(FastAPI):
heartbeat_rate = 15
check_rate = 0.05
last_heartbeat = time.perf_counter()
current_count = app.change_count
while True:
if await request.is_disconnected():
return
if app.change_event and app.change_event.is_set():
app.change_event.clear()
yield """event: reload\ndata: {}\n\n"""
if app.change_count != current_count:
current_count = app.change_count
msg = (
json.dumps(f"{app.reload_error_message}")
if app.change_type == "error"
else "{}"
)
yield f"""event: {app.change_type}\ndata: {msg}\n\n"""
await asyncio.sleep(check_rate)
if time.perf_counter() - last_heartbeat > heartbeat_rate:

View File

@ -38,6 +38,7 @@ from typing import (
Generic,
Iterable,
Iterator,
Literal,
Optional,
TypeVar,
)
@ -123,7 +124,6 @@ class SourceFileReloader(BaseReloader):
watch_module_name: str,
demo_file: str,
stop_event: threading.Event,
change_event: threading.Event,
demo_name: str = "demo",
) -> None:
super().__init__()
@ -131,7 +131,6 @@ class SourceFileReloader(BaseReloader):
self.watch_dirs = watch_dirs
self.watch_module_name = watch_module_name
self.stop_event = stop_event
self.change_event = change_event
self.demo_name = demo_name
self.demo_file = Path(demo_file)
@ -145,8 +144,9 @@ class SourceFileReloader(BaseReloader):
def stop(self) -> None:
self.stop_event.set()
def alert_change(self):
self.change_event.set()
def alert_change(self, change_type: Literal["reload", "error"] = "reload"):
self.app.change_type = change_type
self.app.change_count += 1
def swap_blocks(self, demo: Blocks):
old_blocks = self.running_app.blocks
@ -154,7 +154,7 @@ class SourceFileReloader(BaseReloader):
if old_blocks:
reassign_keys(old_blocks, demo)
demo.config = demo.get_config_file()
self.alert_change()
self.alert_change("reload")
NO_RELOAD = True
@ -281,6 +281,8 @@ def watchfn(reloader: SourceFileReloader):
)
traceback.print_exc()
mtimes = {}
reloader.alert_change("error")
reloader.app.reload_error_message = traceback.format_exc()
continue
demo = getattr(module, reloader.demo_name)
reloader.swap_blocks(demo)

View File

@ -154,6 +154,13 @@
};
}
export function add_new_message(
message: string,
type: ToastMessage["type"]
): void {
messages = [new_message(message, -1, type), ...messages];
}
let _error_id = -1;
let user_left_page = false;

View File

@ -302,6 +302,11 @@
const { host } = new URL(api_url);
let url = new URL(`http://${host}/dev/reload`);
eventSource = new EventSource(url);
eventSource.addEventListener("error", async (e) => {
new_message_fn("Error reloading app", "error");
// @ts-ignore
console.error(JSON.parse(e.data));
});
eventSource.addEventListener("reload", async (event) => {
app.close();
app = await Client.connect(api_url, {
@ -372,6 +377,8 @@
}
};
let new_message_fn: (message: string, type: string) => void;
onMount(async () => {
intersecting.register(_id, wrapper);
});
@ -449,6 +456,7 @@
{autoscroll}
bind:ready
bind:render_complete
bind:add_new_message={new_message_fn}
show_footer={!is_embed}
{app_mode}
{version}