Search code examples
rcachingshiny

Reactive Timer That Updates For all users Shiny R


I have a shiny app that pulls data from my mongo database and displays it in table format. Every 30 minutes the data is changed in my database. Currently, every time a new user logs in, the data is pulled for that single user. I would like something that caches the data but updates it every 30 minutes for all users. That way everytime someone logs in the data is not pulled (slow since R is single threaded). Below is an example of what i currently have.

library(shiny)


ui <- fluidPage(

    titlePanel("Old Faithful Geyser Data"),

   
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30)
        ),

      
        mainPanel(
           plotOutput("distPlot")
        )
    )
)

# create connection to mongo       
mongo.db = mongo(collection, db, url)

server <- function(input, output) {

    #pull data from mongo
      mydata = reactive({
          df = mongo.db$find()
       })
   

    output$distPlot <- renderPlot({
       mydata()
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

Instead I would like something that looks like this

library(shiny)


ui <- fluidPage(

  
    titlePanel("Old Faithful Geyser Data"),

   
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30)
        ),

      
        mainPanel(
           plotOutput("distPlot")
        )
    )
)

   #create connection to mongo
   mongo.db = mongo(collection, db, url)

 #pull in data for all users after 30 minutes.
 mydata = if(its been 30 minutes){ pull and cache data mongo.db} else {do nothing}

server <- function(input, output) {

     

    output$distPlot <- renderPlot({
       mydata()
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

##Edit after seeing Waldi's answer. The file is not updating even though i have just updated the passwords database that is being hosted on mongo. This app is being hosted on shinyapps.io

DBdata = passwords$find()
saveRDS(DBdata,'DBdata.rds')
mydata <- reactiveFileReader(interval = 1000 * 60 * 2, 
                             session = NULL,
                             'DBdata.rds',
                              readRDS)

# Define server logic required to draw a histogram
shinyServer(function(input, output, session) {

  
  output$volscanner = renderDataTable(
    mydata()
  )
 })
  

Solution

  • You could separate data updating and data use.

    Data updating

    Use crontab to run regularly a data updating script, see this link.
    The script should read data from database and save the result on the server :

    conn <- dbConnect(...)
    DBdata <- dbGetQuery(conn,...)
    saveRDS(DBdata,'data\DBdata.rds')
    

    Data use

    Use in server.R a multi-session reactive file reader to update data regularly for all sessions :

    mydata <- reactiveFileReader(interval = 1000 * 60 * 30, 
                                 session = NULL,
                                 'data\DBdata.rds',
                                  readRDS)
    server <- function(input, output) {
        output$distPlot <- renderPlot({
           mydata()
        })
    ...
    }
    

    If DB query is fast enough, you could skip the data updating part and use reactivePoll to query directly the DB.