How to Exit a Shiny App and Return a Value

How to exit a Shiny app and return a value

There is a stopApp function that stops the running app and returns an optional value:

myValue <- runApp(list(
ui = bootstrapPage(
numericInput('n', 'Number of obs', 100),
actionButton("myBtn", "Press ME!"),
plotOutput('plot')
),
server = function(input, output, session) {
output$plot <- renderPlot({ hist(runif(input$n)) });
observe({
if(input$myBtn > 0){
stopApp(7)
}
})
}
))

On stopping:

> myValue
[1] 7

How does one terminate all processes upon Shiny app end?

@PorkChop's comment is pointing in the right direction. However, I'd recommend using processx::process rather than run as it provides us with methods to control the started process from within R. See ?process. (run by the way is also based on the process class.)

The main problem here is, that running the process synchronously (wait=TRUE) blocks the R session. Accordingly onStop won't fire until R is back in control.
Therefore you can't trigger anything once the browser window was closed because the shiny-session continues to run until the external program is finished and R can close the shiny-session.

On session end, the below code checks if the asynchronously started process is still alive and kills it if necessary (tested on windows only).

library(shiny)
library(processx)

ui <- fluidPage(
actionButton("runBtn", label="Run a program that consumes many resources"),
actionButton("stopSession", "Stop session")
)

server <- function(input, output, session) {

myProcess <- NULL

observeEvent(input$stopSession, {
cat(sprintf("Closing session %s\n", session$token))
session$close()
})

observeEvent(input$runBtn,
{
if(Sys.info()[["sysname"]]=="Windows"){
writeLines(text = c("ping 127.0.0.1 -n 60 > nul"), con = "sleep.bat")
myProcess <<- process$new("cmd.exe", c("/c", "call", "sleep.bat"), supervise = TRUE, stdout = "")
} else {
myProcess <<- process$new("sleep", "60", supervise = TRUE, stdout = "")
}
# myProcess$wait() # wait for the process to finish
})

onStop(function(){
cat(sprintf("Session %s was closed\n", session$token))
if(!is.null(myProcess)){
if(myProcess$is_alive()){
myProcess$kill()
}
}

})
}

shinyApp(ui, server)

Regarding the different session callback functions see this related post.


As requested here the process is wrapped in a reactiveVal:

library(shiny)
library(processx)

ui <- fluidPage(
actionButton("runBtn", label="Run a program that consumes many resources"),
actionButton("stopSession", "Stop session")
)

server <- function(input, output, session) {

myProcess <- reactiveVal(NULL)

observeEvent(input$stopSession, {
cat(sprintf("Closing session %s\n", session$token))
session$close()
})

observeEvent(input$runBtn,
{
if(Sys.info()[["sysname"]]=="Windows"){
writeLines(text = c("ping 127.0.0.1 -n 60 > nul"), con = "sleep.bat")
myProcess(process$new("cmd.exe", c("/c", "call", "sleep.bat"), supervise = TRUE, stdout = ""))
} else {
myProcess(process$new("sleep", "60", supervise = TRUE, stdout = ""))
}
# myProcess()$wait() # wait for the process to finish
})

onStop(function(){
cat(sprintf("Session %s was closed\n", session$token))
if(!is.null(isolate(myProcess()))){
if(isolate(myProcess()$is_alive())){
isolate(myProcess()$kill())
}
}

})
}

shinyApp(ui, server)

How to return value from R Shiny Session

After running and closing the app:

customcolors <- scan("colorfile.txt", character())
customcolors

# [1] "#a96337" "#f0ecb0" "#4a4000" "#001a24"

Or run the app with:

customcolors <- runApp(CherryPickPalette("BiryaniRice","Kulfi","Haveli2"))

How to stop resetting a variable in R-Shiny?

You can define it as a reactive value:

server <- shinyServer(function(input, output, session) { 
level_init <- reactiveValues(level="Value1")
level_react <- reactive({
level_init$level <- "Value2"
})
print(isolate(level_init$level))
observeEvent(input$Reset,{
output$graph <- renderPlot({ plot(1, 1) }) }, ignoreNULL = F)
# interaction click in graph
observe({
if(is.null(input$plot_click$x)) return(NULL)
x <- sample(20:30,1,F)
level_react()
print(level_init$level)
isolate({
output$graph <- renderPlot({
draw.single.venn(x)
})
})

})

})
shinyApp(ui=ui,server=server)

Disconnect from PostgreSQL when close R Shiny App

Do you know about the onSessionEnded of the session variable?

Here's a very basic example that sets a random session id to each user and when they close the window, a function runs that says what session id was closed. It's just a proof of concept, you can tailor it to your database needs trivially I hope

runApp(shinyApp(
ui = fluidPage(
textOutput("sessionId")
),
server = function(input, output, session) {
sessionId <- as.integer(runif(1, 1, 100000))
output$sessionId <- renderText(paste0("Session id: ", sessionId))
session$onSessionEnded(function() {
cat(paste0("Ended: ", sessionId))
})
}
))

Edit:

Op said he needs the variable to be reactive, so here's a modification that I believe would allow him what he wants

runApp(shinyApp(
ui = fluidPage(
textOutput("sessionId")
),
server = function(input, output, session) {
values <- reactiveValues(sessionId = NULL)
values$sessionId <- as.integer(runif(1, 1, 100000))
output$sessionId <- renderText(paste0("Session id: ", values$sessionId))
session$onSessionEnded(function() {
observe(cat(paste0("Ended: ", values$sessionId)))
})
}
))

Disclaimer: I'm not sure if putting the observe inside the onSessionEnded callback is the best approach. This works, but I can't vouch for it's "correctness".

How to stop end shiny session by closing the browser

If you want to plot your histogram while the session is active, take the second option. As mentioned by @Waldi the first option plots your histogram when the session is ended, and the user will thus never see the histogram. See here an example of the two options:

First option: we never see the table

rm(list=ls())

library(shiny)

doshiny <- function() {
app=shinyApp(
ui = fluidPage(
textInput("textfield", "Insert some text", value = "SomeText"),
dataTableOutput('table')
),
server = function(input, output, session) {

session$onSessionEnded(function() {
output$table <- renderDataTable(iris)
stopApp()
})
}
)
runApp(app)
}

openshiny <- function() {
doshiny()
print("Finished.")
}

openshiny()

Second option: we see the table

rm(list=ls())

library(shiny)

doshiny <- function() {
app=shinyApp(
ui = fluidPage(
textInput("textfield", "Insert some text", value = "SomeText"),
dataTableOutput('table')
),
server = function(input, output, session) {
output$table <- renderDataTable(iris)
session$onSessionEnded(function() {

stopApp()
})
}
)
runApp(app)
}

openshiny <- function() {
doshiny()
print("Finished.")
}

openshiny()


Related Topics



Leave a reply



Submit