使用 Shiny 部署的 R 应用程序崩溃 'could not find function "httpdPort"'

Deployed R app with Shiny crash with 'could not find function "httpdPort"'

我有一个使用 Shiny 构建的应用程序(教程,其中 ui.Rserver.R 取自此处:http://shiny.rstudio.com/tutorial/lesson1/)。 我在 shiny-frontend 文件夹中有这两个文件,如果我在 RStudio 中本地 runApp("shiny-frontend") - 一切正常,我在浏览器中看到教程。

现在我希望通过 cloudfoundry 将同一个应用程序放入 Bluemix。我正在使用这个:http://www.ibm.com/developerworks/library/ba-rtwitter-app/ 作为教程,但遇到错误。

我有一个 start.r 文件,我 运行 作为 R -f ./start.r --gui-none --no-save。我正在使用 https://github.com/virtualstaticvoid/heroku-buildpack-r 构建包。

我的 start.r 看起来像这样(取自 bluemix 教程,稍作修改):

library(shiny)

if (Sys.getenv('VCAP_APP_PORT') == "") {
  print("Running Shiny")
  runApp("shiny-frontend")
} else {
  # In case we're on Cloudfoundry, run this:
  print('running on CF')

  # Starting Rook server during CF startup phase - after 60 seconds start the actual Shiny server
  library(Rook)
  myPort <- as.numeric(Sys.getenv('VCAP_APP_PORT'))
  myInterface <- Sys.getenv('VCAP_APP_HOST')
  status <- -1

  # R 2.15.1 uses .Internal, but the next release of R will use a .Call.
  # Either way it starts the web server.
  if (as.integer(R.version[["svn rev"]]) > 59600) {
    status <- .Call(tools:::startHTTPD, myInterface, myPort)
  } else {
    status <- .Internal(startHTTPD(myInterface, myPort))
  }

  if (status == 0) {
    unlockBinding("httpdPort", environment(tools:::startDynamicHelp))
    assign("httpdPort", myPort, environment(tools:::startDynamicHelp))

    s <- Rhttpd$new()
    s$listenAddr <- myInterface
    s$listenPort <- myPort

    s$print()
    Sys.sleep(60)
    s$stop()
  }


  # run shiny server
  sink(stderr())
  options(bitmapType='cairo')
  getOption("bitmapType")
  print("test")
  write("prints to stderr", stderr())
  write("prints to stdout", stdout())
  write(port, stdout())
  runApp('shiny-frontend',port=myPort,host="0.0.0.0",launch.browser=F)
}

我的 init.r 看起来像这样:

install.packages("shiny", clean=T)
install.packages("Rook", clean=T)

然后当我 运行 时,一切都已正确部署,但是当我尝试按路线走时,我在日志中看到错误:

* ERR Calls: <Anonymous> -> startDynamicHelp
* ERR Execution halted
* ERR Error in startDynamicHelp(FALSE) : could not find function "httpdPort"

我还注意到每次分配的端口都不一样,这很奇怪而且 bluemix 仪表板中的路由没有提到它。但是我将端口输出到日志,并使用那个数字。

而且我的做法似乎有点太复杂了,所以如果有人能提出更简单的方法,我将不胜感激

我花了一段时间才明白这个错误是由 R 抛出的,因为它找不到 函数(不是值)httpdPort。不是将 httpdPort 绑定到一个函数,而是将它绑定到一个值。 s$stop() 行引起了麻烦。它调用 startDynamicHelp 假设 httpdPort 是在环境 tools.

中定义的函数

要解决此问题,您可以将代码中的块 if (status == 0){...} 更改为:

if (status == 0) {
    getSettable <- function(default){
                       function(obj = NA){if(!is.na(obj)){default <<- obj};
                                  default}
                   }
    myHttpdPort <- getSettable(myPort)
    unlockBinding("httpdPort", environment(tools:::startDynamicHelp))
    assign("httpdPort", myHttpdPort, environment(tools:::startDynamicHelp))

    s <- Rhttpd$new()
    s$listenAddr <- myInterface
    s$listenPort <- myPort

    s$print()
    Sys.sleep(60)
    s$stop()
}