diff --git a/CHANGELOG.md b/CHANGELOG.md index 30f93aad9..a5a9cefd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes +* Fixed issue where apps run in Workbench were unexpectedly crashing. Apps running in Workbench will now have `ws_per_message_deflate=False` enforced. (#2005) + * Fixed an issue where the `
` areas of `ui.page_sidebar()` and `ui.page_navbar()` (with a `sidebar`) were made to be a fillable containers even when `fillable=False`. (#1816) * Fixed an issue where the `.update_user_input()` method on `ui.Chat()` isn't working in shinylive. (#1891) diff --git a/shiny/_main.py b/shiny/_main.py index 30db3232c..65b083139 100644 --- a/shiny/_main.py +++ b/shiny/_main.py @@ -9,6 +9,7 @@ import re import sys import types +import warnings from pathlib import Path from typing import Any, Optional @@ -20,6 +21,7 @@ from . import __version__, _autoreload, _hostenv, _static, _utils from ._docstring import no_example +from ._hostenv import is_workbench from ._typing_extensions import NotRequired, TypedDict from .bookmark._bookmark_state import shiny_bookmarks_folder_name from .express import is_express_app @@ -399,6 +401,8 @@ def run_app( maybe_setup_rsw_proxying(log_config) + _set_workbench_kwargs(kwargs) + uvicorn.run( # pyright: ignore[reportUnknownMemberType] app, host=host, @@ -713,6 +717,18 @@ class ReloadArgs(TypedDict): reload_dirs: NotRequired[list[str]] +def _set_workbench_kwargs(kwargs: dict[str, Any]) -> None: + if is_workbench(): + if kwargs.get("ws_per_message_deflate"): + # Workaround for nginx/uvicorn issue within Workbench + # https://github.com/rstudio/rstudio-pro/issues/7368#issuecomment-2918016088 + warnings.warn( + "Overwriting kwarg `ws_per_message_deflate=True` to `False` to avoid breaking issue in Workbench", + stacklevel=2, + ) + kwargs["ws_per_message_deflate"] = False + + # Check that the version of rsconnect supports Shiny Express; can be removed in the # future once this version of rsconnect is widely used. The dependency on "packaging" # can also be removed then, because it is only used here. (Added 2024-03) diff --git a/tests/pytest/test_main.py b/tests/pytest/test_main.py new file mode 100644 index 000000000..12b2b5eac --- /dev/null +++ b/tests/pytest/test_main.py @@ -0,0 +1,50 @@ +import warnings +from typing import Any, Dict + +import pytest + +from shiny._main import _set_workbench_kwargs + + +def test_workbench_kwargs_if_url_set(monkeypatch: pytest.MonkeyPatch): + """ + Test that the `ws_per_message_deflate` kwarg is set to False when + RS_SERVER_URL and RS_SESSION_URL are set in the environment. + This is to avoid breaking issues in Workbench. + If the kwargs are set to True, a warning is raised and the value is set to False. + """ + # Workbench URL is set, kwargs are not + monkeypatch.setenv("RS_SERVER_URL", "any_string") + monkeypatch.setenv("RS_SESSION_URL", "any_string") + + kwargs: Dict[str, Any] = {} + _set_workbench_kwargs(kwargs) + assert kwargs.get("ws_per_message_deflate") is False + + # kwarg have been set to True + kwargs = { + "ws_per_message_deflate": True, + } + with pytest.warns(UserWarning): + warnings.warn( + "Overwriting kwarg `ws_per_message_deflate=True` to `False` to avoid breaking issue in Workbench", + UserWarning, + stacklevel=2, + ) + _set_workbench_kwargs(kwargs) + assert kwargs.get("ws_per_message_deflate") is False + + +def test_workbench_kwargs_if_url_not_set(): + """ + Test that the `ws_per_message_deflate` kwarg is not changed if the RS_SERVER_URL and RS_SESSION_URL environment variables are not set. + """ + kwargs: Dict[str, Any] = { + "ws_per_message_deflate": True, + } + _set_workbench_kwargs(kwargs) + assert kwargs.get("ws_per_message_deflate") is True + + kwargs: Dict[str, Any] = {} + _set_workbench_kwargs(kwargs) + assert kwargs.get("ws_per_message_deflate") is None