0
votes

I have developed a Shiny Dashboard, I have several data frames that get imported through reactive file readers, etc.. I have also added a "Generate PDF" button, using downloadButton() in my ui.R code. My server.R code implements the downloadHandler() to handle that request.

On my Windows desktop this all works perfectly. I want this to run on a Linux server I have setup. I had to modify some paths, of course, and Shiny Server runs as root on this box. When I click the "Generate PDF" button on site running on the Linux server, I get an HTTP 500 error almost instantly. I have manually compiled the pdfReport.Rmd file on the Linux server myself and it runs just fine.

I am guessing one of two things:

  1. Somehow the data isn't getting passed the same way on the Linux box as it does on the Windows desktop. This is probably not likely, but it is a possibility.
  2. I have something wrong with my paths so when the temp files get written to start generating the PDF, the system doesn't have the ability or a path doesn't exist to write the file. Possibly my downloadHandler() code is malformed in some way. I think this is a higher possibility than the #1.

Here is my code for the downloadHandler():

output$pdfReport <- downloadHandler(
  # For PDF output, change this to "report.pdf"
  filename = reactive({paste0("/srv/shiny-server/itpod/","ITPOD-",Sys.Date(),".pdf")}),

  content = function(file) {
    # Copy the report file to a temporary directory before processing it, in
    # case we don't have write permissions to the current working dir (which
    # can happen when deployed).

    tempReport <- file.path("/srv/shiny-server/itpod", "pdfReport.Rmd")
    file.copy("report.Rmd", tempReport, overwrite = TRUE)

    params <- list(ilp=updateILP(), ico=updateICO(), sec=updateSecurity(), ppwc=updateWorkPreviousPeriodCompleted(),
                   pow=updateOngoingWorkCABApproved(), pwcr=updatePlannedWorkCABRequested(), epca=updateEmergencyChangesPendingCABApproval(),
                   fac=updateFacilities(), drs=updateDRStatus(), ov=updateOperationalEvents(), sl=updateStaffLocations(),
                   w = updateWeather())

    # Knit the document, passing in the `params` list, and eval it in a
    # child of the global environment (this isolates the code in the document
    # from the code in this app).
    rmarkdown::render(tempReport, output_file = file, params = params, envir = new.env(parent = globalenv())
    )
  }
)

I thought maybe that the path just wasn't writeable, so I tried changing that to /tmp, but that didn't work either. Poking around, I discovered that when I over the "Generate PDF" button, I get a long URL with a "session":

http://my.url.com:3838/itpod/session/d661a858f5679aba26692bc9b4442872/download/pdfReport?w=

I'm starting to wonder if this is the issue and that I'm not writing to a path of the current session or something? This is a new area to me with Shiny. Like I said, on my desktop it works fine, but once I deploy it to the Linux server, it doesn't work correctly. Any help would be much appreciated. Thanks in advance!

1

1 Answers

0
votes

Ok - after much troubleshooting, I figured out that some of the files I had in the shiny webroot that were dependencies for the main pdfReport.Rmd file weren't being seen, since the code copied the report to a temp directory.

Because I didn't want to copy all of the files from my webroot over to the temp, I decided to make the report render within the webroot itself. For me, this isn't a big deal since my shiny app is running as root anyway.

I will fix this now that I have it working, basically my fix will be to do the following:

  1. Make the service run as a normal user
  2. Rather than copy of the files that the report depends on, I will have to statically reference them in the report code.

I apologize for all of those who may have read this and are working on it. My fix was to the code above was the following:

output$pdfReport <- downloadHandler(
      # For PDF output, change this to "report.pdf"
      filename = reactive({paste0("/srv/shiny-server/itpod/","ITPOD-",Sys.Date(),".pdf")}),

      content = function(file) {
        # Copy the report file to a temporary directory before processing it, in
        # case we don't have write permissions to the current working dir (which
        # can happen when deployed).

        report <- file.path(getwd(), "pdfReport.Rmd")
        #tempReport <- file.path(tempdir(), "pdfReport.Rmd")
        #file.copy("pdfReport.Rmd", tempReport, overwrite = TRUE)

        params <- list(ilp=updateILP(), ico=updateICO(), sec=updateSecurity(), ppwc=updateWorkPreviousPeriodCompleted(),
                       pow=updateOngoingWorkCABApproved(), pwcr=updatePlannedWorkCABRequested(), epca=updateEmergencyChangesPendingCABApproval(),
                       fac=updateFacilities(), drs=updateDRStatus(), ov=updateOperationalEvents(), sl=updateStaffLocations(),
                       w = updateWeather())

        # Knit the document, passing in the `params` list, and eval it in a
        # child of the global environment (this isolates the code in the document
        # from the code in this app).
        rmarkdown::render(report, output_file = file, params = params, envir = new.env(parent = globalenv())
        )
      }
    )

  })

Notice, that instead of copying the file to a temp directory, I just specify the file in the current working directory.