【问题标题】:Error at run shiny app in the background with system()?使用 system() 在后台运行闪亮的应用程序时出错?
【发布时间】:2021-01-08 22:31:19
【问题描述】:

我找到了两种在后台运行闪亮应用程序的方法:

第一个

path_aux = "R -e \"shiny::runApp('inst/app.R', launch.browser = TRUE)\""
system(path_aux, wait = FALSE)

问题

似乎这个替代方案运行了我闪亮应用程序的不同版本,我的意思是,我有一个名为 fileName 的变量,在运行我的应用程序之前我运行了这一行:

fileName <- "OpenTree"

但是当我跑步时

path_aux = "R -e \"shiny::runApp('inst/app.R', launch.browser = TRUE)\""
system(path_aux, wait = FALSE)

我的变量fileName 有另一个值,总是一样的,我不知道它在哪里。

第二种选择

我用其他替代品进行测试

rstudioapi::jobRunScript(path = "inst/shiny-run.R")```

shiny-run.R

shiny::runApp(appDir = "inst/app.R",port = 3522)

这个替代方案很好用

我想使用第一个,因为也许我想让多个窗口运行我的应用程序,这是一个包我只想知道这个值“fileName”来自哪里。我不知道系统是否拍摄快照或类似的东西。

谢谢

【问题讨论】:

  • system 不擅长运行任何参数中包含空格的命令。我建议callr(仅限于 R 实例)或processx(通用,用于处理同步和异步进程的更好的 API)。
  • 关于fileName 是不同值的问题...在使用system(甚至processx)。使用callr 时可能可用,这可能用一种解决方案解决两个问题。
  • 您是否考虑过在您的计算机上运行一个免费的 shiny-server 实例?根据您的技术技能,docker 镜像不会太难,并且可以提供比启动多个 R 实例更多的功能。
  • 我将shinyapp 部署为库,这就是我想在后台运行该应用程序的原因。我不认为docker是我最好的选择,因为我构建了一些功能,请参考这个链接(stackoverflow.com/questions/65588060/…)谢谢
  • “作为库”“构建一些功能”与docker的可用性无关。抱歉,我的回答相当长,但它是在本地运行闪亮应用程序的全功能选项。

标签: r shiny background


【解决方案1】:

由于我在评论中推荐了它,我将在这里稍微正式化一下:Docker。事后看来,这个答案变成了比预期更多的教程/方法。我希望这不会令人生畏;这些步骤实际上非常简单,一旦你有可用的 docker,你可能只需要运行类似的东西:

$ docker run --rm -d -p 3838:3838                                    \
  -v c:/Users/r2/R/win-library/4.0/shiny/examples/:/srv/shiny-server \
  -v c:/Users/r2/shinylogs/:/var/log/shiny-server/                   \
  -v c:/Users/r2/R/otherlibrary/:/mylibrary/                         \
  rocker/shiny-verse:4.0.3

以下内容很少是 R 代码,它们都在 shell/终端中。我正在使用 git-bash 在 win10 上对其进行测试,但这应该可以在 macos 或 linux 上运行,只需很少的修改。

目录

  1. 如果未安装,请安装 docker。
  2. 拉出闪亮的服务器映像。
  3. 启动闪亮服务器容器(使用 app-dir 挂载)。
  4. 浏览到正在运行的应用程序。更新您的应用,更改会立即生效。
  5. 停止服务器(当天完成后)。

然后是日志的两个部分以及处理Other Packages的一些方法。

内容

  1. 如果不可用,请确保 docker 可用:

    $ docker -v
    Docker version 20.10.2, build 2291f61
    

    如果没有找到,那么Get Docker 是安装它的最佳资源。

  2. 拉出一张可用的图片。我正在使用rocker/shiny-verse 进行演示,其中包括闪亮的和所有tidyverse 依赖项(图像大小为1.95GB),但也有rocker/shiny 稍小(1.56GB)。 (文档在第二个链接中更详细。)

    我强烈建议使用特定版本而不是 :latest(或无版本),因为您可能需要密切模仿笔记本电脑上的开发环境。这个正在运行的容器不会使用你本地的 R,它有自己的。因此,您可能只在主机上安装了 R-3.6,并在容器中使用 R-4.0.3。使用您正在测试/开发的相同 (major.minor) 版本。

    $ docker pull rocker/shiny-verse:4.0.3
    Using default tag: latest
    latest: Pulling from rocker/shiny-verse
    a4a2a29f9ba4: Already exists
    127c9761dcba: Already exists
    d13bf203e905: Already exists
    4039240d2e0b: Already exists
    fffc4b622efe: Pull complete
    c265253654a5: Pull complete
    e0161c6ad391: Pull complete
    8e7558fa9ec5: Pull complete
    Digest: sha256:ce760db38a4712a581aa6653cf3a6562ddea9b48d781aad4f9582b8056401317
    Status: Downloaded newer image for rocker/shiny-verse:4.0.3
    docker.io/rocker/shiny-verse:4.0.3
    
  3. 确定要“挂载”的(主机)目录。我将使用与 R 的 shiny 包一起安装的示例,但您可以使用任何东西。有两种选择:

    • 单一应用

      Mount:应用目录本身,例如c:/Users/r2/R/win-library/4.0/shiny/examples/01_hello/

      使用:http://localhost:3838/ 将运行该应用程序。

    • 多个应用程序目录

      Mount:包含其他应用程序目录的目录,例如,c:/Users/r2/R/win-library/4.0/shiny/examples/

      使用:http://localhost:3838/ 将显示应用程序的目录,http://localhost:3838/01_hello/ 将运行第一个应用程序。

    在您的情况下,您可能会选择/path/to/your/package/inst/ 之类的内容,然后选择上面的单应用选项。

    根据rocker/shiny 的文档,我们将把它安装在/srv/shiny-server/

    $ docker run --rm -d -p 3838:3838 \
      -v c:/Users/r2/R/win-library/4.0/shiny/examples/:/srv/shiny-server \
      rocker/shiny-verse:4.0.3
    ba4654d541ef39fb4882364446ece0b516e518baf946c21d1857565f05acd2c5
    

    (仅供参考:-p 3838:3838 需要将服务器“暴露”在正在运行的闪亮服务器“容器”之外。第一个数字是您的计算机可见的,第二个数字必须保持 3838 并且是服务器的实际上是在内部运行。如果你不包括这个,你就不会看到它。)

  4. 将您的浏览器指向http://localhost:3838(或您在上面分配的任何端口),您应该会看到应用程序(如果是单个应用程序)或应用程序目录。

  5. 完成后,杀死(停止)容器:

    $ docker stop exciting_gagarin
    

日志

有时您会想要/需要查看日志(例如,警告/错误)。有两种类型的日志:

  • 服务器日志,可通过运行访问

    docker logs -f exciting_gagarin
    

    Ctrl-C 停止日志,服务器继续运行。)

  • app 日志(每个会话)。为此,您可以跳入正在运行的容器并查看日志,但是当容器停止时,这些日志将被删除(因为 docker 容器内的文件默认为临时文件)......而这可能不方便。相反,您可以通过在docker run 命令中包含此卷挂载指令来将应用日志挂载到本地目录:

    -v c:/Users/r2/shinylogs/:/var/log/shiny-server/
    

    当应用程序正在运行并发生警告/错误时,您应该会看到如下文件:

    $ ls -l c:/Users/r2/shinylogs/
    total 5
    -rw-r--r-- 1 r2 197121 112 Jan  8 08:38 shiny-server-shiny-20210108-133524-43293.log
    -rw-r--r-- 1 r2 197121 237 Jan  8 08:53 shiny-server-shiny-20210108-135551-35903.log
    -rw-r--r-- 1 r2 197121 271 Jan  8 08:54 shiny-server-shiny-20210108-135610-44445.log
    -rw-r--r-- 1 r2 197121 271 Jan  8 08:54 shiny-server-shiny-20210108-135612-40369.log
    -rw-r--r-- 1 r2 197121 145 Jan  8 08:57 shiny-server-shiny-20210108-140001-43857.log
    

其他包

您的包可能不包含在rocker/shiny 或rocker/shiny-verse 中。不要害怕!请遵循以下说明:

  1. 创建一个本地(不是容器内)目录,您将在其中安装这些缺失的软件包。我生成了一个单独的文件夹,因为主机操作系统可能与容器内操作系统(debian)不同,在这种情况下,包的格式可能不正确。我将使用c:/Users/r2/R/otherlibrary。我将在主机操作系统“R”实例中使用此路径。

  2. 将卷挂载添加到您的命令中,使其在容器内可用:

    -v c:/Users/r2/R/otherlibrary/:/mylibrary/
    

    如果你有一个容器正在运行,你需要docker stop它,然后通过这个添加重新run它。

  3. 在您的应用中,添加

    .libPaths( c("/mylibrary", .libPaths()) )
    

    关于此的两件事:(1)R 需要在备用目录中查找; (2) 如果在主机上运行并且"/mylibrary" 不存在,这不会造成任何伤害。如果愿意,您可以选择包含条件 if (dir.exists("/mylibrary"))...

  4. 安装额外的 CRAN 包。

    我看到很多应用都是内置的,可以根据需要安装包,比如

    if (!require("ggrepel")) install.packages("ggrepel")
    

    这没有错(正确使用 requirelibrary),但这不是我喜欢的做事方式。

    另一种方法是手动安装这些所需的包,我们可以通过在容器中输入 R 并安装到适当的库路径来做到这一点。

    $ docker exec -it exciting_gagarin R
    R version 4.0.3 (2020-10-10) -- "Bunny-Wunnies Freak Out"
    Copyright (C) 2020 The R Foundation for Statistical Computing
    Platform: x86_64-pc-linux-gnu (64-bit)
    
    R is free software and comes with ABSOLUTELY NO WARRANTY.
    You are welcome to redistribute it under certain conditions.
    Type 'license()' or 'licence()' for distribution details.
    
    R is a collaborative project with many contributors.
    Type 'contributors()' for more information and
    'citation()' on how to cite R or R packages in publications.
    
    Type 'demo()' for some demos, 'help()' for on-line help, or
    'help.start()' for an HTML browser interface to help.
    Type 'q()' to quit R.
    
    > .libPaths( c("/mylibrary", .libPaths()) )
    > .libPaths()
    [1] "/mylibrary"                    "/usr/local/lib/R/site-library"
    [3] "/usr/local/lib/R/library"
    > install.packages("ggrepel")
    Installing package into ‘/mylibrary’
    (as ‘lib’ is unspecified)
    trying URL 'https://packagemanager.rstudio.com/all/__linux__/focal/latest/src/contrib/ggrepel_0.9.0.tar.gz'
    Content type 'binary/octet-stream' length 980180 bytes (957 KB)
    ==================================================
    downloaded 957 KB
    
    * installing *binary* package ‘ggrepel’ ...
    * DONE (ggrepel)
    
    The downloaded source packages are in
            ‘/tmp/RtmpgPG8YS/downloaded_packages’
    > q("no")
    
  5. 非 CRAN 软件包。我意识到您正在开发本地软件包。两个引用的镜像都包含devtools 包,因此通过额外的卷挂载,您可以使用devtools::installdevtools::load_all,或者如果您已经构建了源包,您可以使用install.packages("/mylibrary/mypackage.tar.gz")

更多关于为什么可能需要不同包库的详细信息:编译代码。例如,当我在 Windows 上安装ggrepel(一个示例)时,其中的文件是

ggrepel/libs/i386/ggrepel.dll
ggrepel/libs/x64/ggrepel.dll

它们是特定于 Windows 操作系统的编译库。当我在 linux 上安装相同的包时,我没有这些库,而是看到了

ggrepel/libs/ggrepel.so

我为什么说linux?因为这些 rocker/shiny* 图像在后台运行 linux ......即使您的主机操作系统是 windows 或 macos。

文件格式不兼容,因此无法重命名。许多软件包可能开箱即用(尚未测试),但如果您尝试将 host-OS R 库路径安装到容器中并看到错误,请考虑此讨论。

docker注意事项

(如果你不熟悉。)

  • 一般来说,正在运行的 docker 容器中的所有内容都是短暂的,这意味着当容器停止时,日志和保存的文件都会消失。解决这个问题的方法是像我们上面所做的那样使用卷挂载。在这种情况下,如果应用程序将文件保存到自己的目录中,那么您将在主机操作系统的/path/to/mypackage/inst/... 下看到它。

  • 根据您的操作系统配置,这仅在本地主机上可见,因此可以是 http://localhost:3838http://127.0.0.1:3838(它们并不总是相同,例如有时是 windows)。如果您需要将它暴露给您网络上的其他计算机......那么我建议您对此进行一些研究。在 docker 中运行服务器并将其暴露给网络的其余部分存在风险和后果。

【讨论】:

  • 这个答案对您有帮助吗?你能解决你的问题吗?
猜你喜欢
  • 2015-10-21
  • 2013-07-08
  • 1970-01-01
  • 2016-02-09
  • 2021-04-30
  • 1970-01-01
  • 2017-02-19
  • 1970-01-01
  • 2016-02-24
相关资源
最近更新 更多