Transient data storage for different users - how to?

...and how to avoid overspilling to an other user?

Idea: I am working on a quite complex shiny-project, that might be a bit different to a "typical" shiny project.(?) It will be hosted on shinyapps.io (the first draft is there already - not sure if I finish it for the competition deadline!). Basically the user uploads some data, it will be interactively converted by the user and in the end a lot of plots and tables are generated, that are intended to be received by the user. And yes, I expect a lot of people using it, so there a chances it will be run simultanously by different persons.

Background I read a lot of articels (e.g. the "persistant data storage with shiny") and came to the conclusion that it should be the best option to store the data first locally on the server and then zip everything and download the zip file. Initially I just created a "results" folder, but then I noticed that 2 different users, running the app at the same time basically share the folder, each user also gets the results from the other one. Surprisingly the internal data-sets are still different.
Currently I tried to define a temporary folder to store the data in there. It seems that the R-temp-folder (as RtmpYn6Lt6) is created per session, so as long as the app is running the next user will have the same folder, so I create another one using file_temp from fs-package (temp.dir from base did the same but was somehow inconsistent)

Here is an example:

# Shiny app to test temporary folder structure
# server.R

library(shiny)
library(tidyverse)  # yes I know, library ggplot2 would be sufficient here
library(zip)

### FS package  # I thought this will help, but it has the same problems 
library(fs)


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

  # Create temporary directory
  TempDir = dir_create(file_temp(pattern="")) 
  TempDir
  
  # Defining the subdirectories to have easier access for writing results
  PlotDir = paste0(TempDir,"/Results/Plots")
  TableDir = paste0(TempDir,"/Results/Tables")
  QCDir = paste0(TempDir,"/Results/QC")
  
  dir_create(c(PlotDir, TableDir, QCDir))
  
  output$Text_Output = renderText({
         paste("working directory: ", getwd(), "\n",
            "temp directory is: ", TempDir, "\n")  
    })

  observeEvent(input$Plots, {
    ## Generating some demo-plots in the plot-folder
    theme_set(theme_classic())
    
    #Plot 1
    ggplot(mtcars, aes(x = disp, y = mpg))  +
      geom_point(size = 3, colour = "blue") +
      labs(title = "Plot 1 - mtcars",
           caption = TempDir)
     ggsave("Plot1.png", 
            path = PlotDir, 
            width = 10, height = 6, units = "cm")
    #Plot 2
    ggplot(mtcars) +
      geom_violin(aes(x = as.factor(cyl), y = hp, 
                      fill = cyl)) +
      labs(title = "Plot 2 - Violins",
           caption = TempDir)
    
    ggsave("Plot2.png", 
           path = PlotDir, 
           width = 10, height = 6, units = "cm")
    
   # Plot 3
    ggplot(diamonds, aes(price, fill = cut)) +
      geom_histogram(binwidth = 500) +
      labs(title = "Plot 3 - Diamonds",
           caption = TempDir)
    
    ggsave("Plot3.png", 
           path = PlotDir, 
           width = 10, height = 6, units = "cm")
    
    }) ## End of observe Plots
  
  observeEvent(input$Tables, { 
    ## Generating some demo-tables
    #Table 1
      write_csv(mtcars, paste0(TableDir,"/Table1_cars.csv"))
    #Table 2
      write_csv(iris, paste0(TableDir,"/Table2_iris.csv"))
    #Table 3
      write_csv(ToothGrowth, paste0(TableDir,"/Table3_toothgrowth.csv"))
    })

  observeEvent(input$Inventory, { 
     ## Show the files present in the folder 
     output$Results  = renderPrint(
       list.files(path=paste0(TempDir,"/Results"),
                  recursive = TRUE, full.names = TRUE) )    })  
  
  observeEvent(input$Zip, { 
    ## Zipping everything   
    setwd(TempDir)  # Only(?) this works!
    zip("results_setwd.zip", "Results")      })  
  
  output$DL_Results <- downloadHandler(
    ## Download zip file
    filename = "Results.zip",
    content = function(file) {
      file.copy("results_setwd.zip", file)
    },
    contentType = "application/zip")    
})
# ui.R
shinyUI(fluidPage(
  
  titlePanel("Test for temp directory"),
  # Sidebar  
  sidebarLayout(
    sidebarPanel(
      actionButton("Plots", "Generate Plots"),
      actionButton("Tables", "Generate Tables")
    ),
  mainPanel(
      verbatimTextOutput("Text_Output"),
      actionButton("Inventory", "Show Inventory"),
      verbatimTextOutput("Results"),
      actionButton("Zip", "Generate zip-file"),
      downloadButton("DL_Results", "Download zipped results")
    ))
))

I uploaded this to shinyapps.io as well, tested this in parallel with 2 different computers (different IPs, one was connected via the company VPN) and still there was some spillover. Whenever I create the zip-file it contains the data from the instance executing the zip, but it was available at both sides!
I guess the setwd() makes a problem, but I couldn't find a way to create the zips with absolute paths, it only works with relative path.

Possible options/ directions:

  • Can I just configure Shinyapps to only allow one user per instance?
  • Can I somehow read the session-ID and include this in the temporary folder-generation?
  • Is it a good idea to have a setwd() in the code? Or can I circumvent this by creating a relative path starting somehow from the working/ target directory?
  • Any other ideas?
  • Should I delete the folders when the app is closed, or will this be done anyway from time to time?

Help is very much appreciated!

1 Like

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.