【问题标题】:How to catch all errors from Shiny module call?如何从 Shiny 模块调用中捕获所有错误?
【发布时间】:2020-10-02 05:19:27
【问题描述】:

我想将 Shiny 模块包装成一种“try catch”,以防止它以任何意想不到的方式崩溃。 Module 代表shinydashboard 选项卡之一,因此在其中一个组件发生故障后,该应用程序仍然可用。

我知道使用req 函数在单个错误后不停止应用程序的可能性(例如在this 帖子中提出)但这里的目标是通过减少用户在相当复杂的错误中的成本来实现快速获胜有大量技术债务的应用程序。

预期行为:显示模块崩溃模式后,用户仍然可以使用该应用程序。

可重现的例子:

library(shiny)

counterButton <- function(id, label = "Counter") {
  ns <- NS(id)
  tagList(
    actionButton(ns("button"), label = label),
    verbatimTextOutput(ns("out"))
  )
}

counter <- function(input, output, session) {
  count <- reactiveVal(0)
  observeEvent(input$button, {
    count(count() + 1)
    stop("Test observeEvent error")
  })
  output$out <- renderText({
    count()
  })
  count
}

ui <- fluidPage(
  counterButton("counter1", "Counter #1")
)

server <- function(input, output, session) {
  tryCatch({
    callModule(counter, "counter1")
  }, error = function(err) {
    showNotification(paste("Error: ", err$message), type = "error")}
  )}

shinyApp(ui, server)

我找到了一个部分解决方案(请参阅here),它确实有效,但它涉及应用程序模块代码的更改,这对我来说并不总是可以做到:

tryObserveEvent <- function(eventExpr, handlerExpr, ...) {
  eventExpr <- substitute(eventExpr)
  handlerExpr <- substitute(handlerExpr)

  env <- parent.frame()

  shiny::observeEvent(tryCatch(
    eval(eventExpr, env),
    error = function(e) {
      showNotification(paste("Error: ", e$message), type = "error")
    }
  ),
  {
    tryCatch(
      eval(handlerExpr, env),
      error = function(e) {
        showNotification(paste("Error: ", e$message), type = "error")
      }
    )
  }, ...)
}

【问题讨论】:

    标签: r error-handling shiny user-experience


    【解决方案1】:

    最近我遇到了同样的需求。这是您的示例的一个小尝试。希望能帮助到你。它帮助我,至少开始为我的用例开发一个好的解决方案 - 一个完全模块化的复杂应用程序

    这个解决方案背后的想法是,有一个反应值来监控模块是否成功完成了它的工作。模块中的观察者被包裹在一个 tryCatch 中。我想我可以用 tryCatch 将所有反应组件包装在模块中。 如果反应式或观察者失败,则模块不成功,应用程序中的主服务器功能会监视此行为并通知用户(请参阅主服务器功能中的observeEvent(..)。此外,我从模块服务器。见return(mod_success)

    library(shiny)
    
    counterButton <- function(id, label = "Counter") {
      ns <- NS(id)
      tagList(
        actionButton(ns("button"), label = label),
        verbatimTextOutput(ns("out"))
      )
    }
    
    counter <- function(input, output, session) {
      count <- reactiveVal(0)
    
      mod_success <- reactiveValues(
        success = TRUE,
        error = NULL
      )
      
      observeEvent(input$button, {
          
        tryCatch(
          expr = {
            count(count() + 1)
            if(count() == 4) {
              stop("You cannot count to: ", count())
            } 
          },
          error = function(errr){
            
            mod_success$success <- FALSE
            mod_success$error <- errr$message
            
          }
        )
        
        
      })
      
      output$out <- renderText({
        
        count()
        
      })
      
      return(mod_success)
      
      
    }
    
    ui <- fluidPage(
      
      counterButton("counter1", "Counter #1")
      
    )
    
    server <- function(input, output, session) {
      
      res <- callModule(counter, "counter1")
      
      observeEvent(res$success,{
        
        if(isFALSE(res$success)){
          
          showNotification(paste0("Error: ", res$error), type = "error")
          
        }
        
      })
      
      
    }
    
    shinyApp(ui, server)
    

    【讨论】:

      猜你喜欢
      • 2016-12-07
      • 2018-12-04
      • 1970-01-01
      • 1970-01-01
      • 2011-11-15
      • 2015-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多