rshinyrsconnect

Force rsconnect::deployApp() to fail to test 'on.failure'


I have a shiny application which updates each night via rsconnect::deployApp using a batch file and scheduled task. This process is currently functioning as intended, but currently the only way to confirm the success of the entire procedure is to visit the app and check if the timestamp is updated.

?deployApp shows an on.failure option which will call a function if the deployment fails. I have ideas of how to use this to send a notification if the deploy fails but I haven't been able to test it because I can't actually make the deployApp function fail.

I have tried placing errors in the UI but the app successfully deploys, despite being non-functional in the viewer and on shinyapps.io.

Is there a way to force the deployApp function to fail so I am able to test the on.failure function I am creating?

Here's a small shiny app borrowed from here if needed.

# Global variables can go here
n <- 200


# Define the UI
ui <- bootstrapPage(
  numericInput('n', 'Number of obs', n),
  plotOutput('plot')
)


# Define the server code
server <- function(input, output) {
  output$plot <- renderPlot({
    hist(runif(input$n))
  })
}

# Return a Shiny app object
shinyApp(ui = ui, server = server)

Currently running R v. 4.0.2; rsconnect 0.8.16, shiny 1.5.0

Edit: I tried sneaking a q() into the app. It for sure breaks the app but doesn't interfere with deployApp. The search continues!


Solution

  • My guess is that the on.failure fires when there is an error in the, well, deployment. From that perspective, errors in the code (stop or even q) trigger on.failure only when it tampers with the deployment. Since there is no apparent check of the code itself in deployApp it probably won't work like this.

    Looking at the underlying rsconnect:::openURL (where the on.failure argument is used), we see that on.failure is used in 2 conditions:

    if (!is.null(client$configureApplication)) {
        config <- client$configureApplication(application$id)
        url <- config$config_url
        if (!deploymentSucceeded && validURL(config$logs_url)) {
            url <- config$logs_url
        }
        if (validURL(url)) {
            if (deploymentSucceeded) {
                showURL(url)
            }
            else if (is.function(on.failure)) {
                on.failure(url) ## here
            }
        }
    }
    else if (deploymentSucceeded) {
        showURL(application$url)
    }
    else if (is.function(on.failure)) {
        on.failure(NULL) ## and here
    }
    

    So what I would do to test, is to debug(rsconnect:::openURL) and when the browser opens, I would simply set client$configureApplication <- NULL;deploymentSucceeded <- FALSE and continue with the code.

    However, looking at the code, we see all what will happen is that, on.failure is called. Thus, calling on.failure directly will have the same effect.