Skip to content

Commit

Permalink
feat: send viewer update errors to and re-raise in parent process
Browse files Browse the repository at this point in the history
  • Loading branch information
neindochoh committed Oct 26, 2023
1 parent d16dbb3 commit eca7696
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 46 deletions.
75 changes: 37 additions & 38 deletions renumics/spotlight/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ class SpotlightApp(FastAPI):
"""

# lifecycle
_startup_complete: bool
_loop: asyncio.AbstractEventLoop

# connection
Expand Down Expand Up @@ -120,7 +119,6 @@ class SpotlightApp(FastAPI):

def __init__(self) -> None:
super().__init__()
self._startup_complete = False
self.task_manager = TaskManager()
self.websocket_manager = None
self.config = Config()
Expand Down Expand Up @@ -313,44 +311,45 @@ def update(self, config: AppConfig) -> None:
"""
Update application config.
"""
if config.project_root is not None:
self.project_root = config.project_root
if config.dtypes is not None:
self._user_dtypes = config.dtypes
if config.analyze is not None:
self.analyze_columns = config.analyze
if config.custom_issues is not None:
self.custom_issues = config.custom_issues
if config.dataset is not None:
self._dataset = config.dataset
self._data_source = create_datasource(self._dataset)
if config.layout is not None:
self._layout = config.layout or layouts.default()
if config.filebrowsing_allowed is not None:
self.filebrowsing_allowed = config.filebrowsing_allowed

if config.dtypes is not None or config.dataset is not None:
data_source = self._data_source
assert data_source is not None
self._data_store = DataStore(data_source, self._user_dtypes)
self._broadcast(RefreshMessage())
self._update_issues()
if config.layout is not None:
if self._data_store is not None:
dataset_uid = self._data_store.uid
future = asyncio.run_coroutine_threadsafe(
self.config.remove_all(CURRENT_LAYOUT_KEY, dataset=dataset_uid),
self._loop,
)
future.result()
self._broadcast(ResetLayoutMessage())
try:
if config.project_root is not None:
self.project_root = config.project_root
if config.dtypes is not None:
self._user_dtypes = config.dtypes
if config.analyze is not None:
self.analyze_columns = config.analyze
if config.custom_issues is not None:
self.custom_issues = config.custom_issues
if config.dataset is not None:
self._dataset = config.dataset
self._data_source = create_datasource(self._dataset)
if config.layout is not None:
self._layout = config.layout or layouts.default()
if config.filebrowsing_allowed is not None:
self.filebrowsing_allowed = config.filebrowsing_allowed

if config.dtypes is not None or config.dataset is not None:
data_source = self._data_source
assert data_source is not None
self._data_store = DataStore(data_source, self._user_dtypes)
self._broadcast(RefreshMessage())
self._update_issues()
if config.layout is not None:
if self._data_store is not None:
dataset_uid = self._data_store.uid
future = asyncio.run_coroutine_threadsafe(
self.config.remove_all(CURRENT_LAYOUT_KEY, dataset=dataset_uid),
self._loop,
)
future.result()
self._broadcast(ResetLayoutMessage())

for plugin in load_plugins():
plugin.update(self, config)
for plugin in load_plugins():
plugin.update(self, config)
except Exception as e:
self._connection.send({"kind": "update_complete", "error": e})

if not self._startup_complete:
self._startup_complete = True
self._connection.send({"kind": "startup_complete"})
self._connection.send({"kind": "update_complete"})

def _handle_message(self, message: Any) -> None:
kind = message.get("kind")
Expand Down
27 changes: 20 additions & 7 deletions renumics/spotlight/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class Server:
process: Optional[subprocess.Popen]

_startup_event: threading.Event
_update_complete_event: threading.Event
_update_error: Optional[Exception]

connection: Optional[multiprocessing.connection.Connection]
_connection_message_queue: Queue
Expand Down Expand Up @@ -77,7 +79,7 @@ def __init__(self, host: str = "127.0.0.1", port: int = 8000) -> None:
)

self._startup_event = threading.Event()
self._startup_complete_event = threading.Event()
self._update_complete_event = threading.Event()

self._connection_thread_online = threading.Event()
self._connection_thread = threading.Thread(
Expand Down Expand Up @@ -151,7 +153,6 @@ def start(self, config: AppConfig) -> None:
command.append("--reload")

# start uvicorn

self.process = subprocess.Popen(
command,
env=env,
Expand All @@ -164,7 +165,7 @@ def start(self, config: AppConfig) -> None:
)
if platform.system() != "Windows":
sock.close()
self._startup_complete_event.wait(timeout=120)
self._wait_for_update()

def stop(self) -> None:
"""
Expand Down Expand Up @@ -197,7 +198,6 @@ def stop(self) -> None:
self._port = self._requested_port

self._startup_event.clear()
self._startup_complete_event.clear()

@property
def running(self) -> bool:
Expand All @@ -217,9 +217,21 @@ def update(self, config: AppConfig) -> None:
"""
Update app config
"""
self._update(config)
self._wait_for_update()

def _update(self, config: AppConfig) -> None:
self._app_config = config
self.send({"kind": "update", "data": config})

def _wait_for_update(self) -> None:
self._update_complete_event.wait(timeout=120)
self._update_complete_event.clear()
err = self._update_error
self._update_error = None
if err:
raise err

def get_df(self) -> Optional[pd.DataFrame]:
"""
Request and return the current DafaFrame from the server process (if possible)
Expand All @@ -236,9 +248,10 @@ def _handle_message(self, message: Any) -> None:

if kind == "startup":
self._startup_event.set()
self.update(self._app_config)
elif kind == "startup_complete":
self._startup_complete_event.set()
self._update(self._app_config)
elif kind == "update_complete":
self._update_error = message.get("error")
self._update_complete_event.set()
elif kind == "frontend_connected":
self.connected_frontends = message["data"]
self._all_frontends_disconnected.clear()
Expand Down
6 changes: 5 additions & 1 deletion renumics/spotlight/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,11 @@ def show(
if self not in _VIEWERS:
_VIEWERS.append(self)
else:
self._server.update(config)
try:
self._server.update(config)
except Exception as e:
self.close()
raise e

if not no_browser and self._server.connected_frontends == 0:
self.open_browser()
Expand Down

0 comments on commit eca7696

Please sign in to comment.