Search code examples
ropencpu

OpenCPU: Reuse results from previous session not working


I would like to use save_iris_as_csv to save a .csv file. Then, call catch_url_and_download to download this .csv file using the session returned by save_iris_as_csv. However, the catch_url_and_download does not work, returning an error of

OpenCPU error HTTP 400
cannot open URL 'http://localhost:5656/ocpu/tmp/x06c27c3ac4/files/iris.csv'

The URL can be opened manually. It is just the second R function cannot open it.

Following is my javascript code.

ocpu.call("save_iris_as_csv",{},function(session){
    console.log("save_iris_as_csv is good.")
    console.log(session)
    console.log("trying to call catch_url_and_download.")
    ocpu.call("catch_url_and_download",{
        url:session.loc + "files/iris.csv"
    },function(session2){
        console.log(session2)
    }).fail(function(e){
        console.log("catch_url_and_download failed. Cannot open URL xxx.")
        alert(e.responseText)
    })
})

Following is my R codes.

save_iris_as_csv = function(){
  write.csv(iris,"iris.csv")
}
catch_url_and_download = function(url){
  download.file(url,"iris.csv")
}

I am using Windows OS.


Solution

  • The problem here is that R is single threaded and hence the httpuv webserver (on which the opencpu single-user server is based) can only serve a single request at a time. In your example you've created a grid lock.

    Your example makes a request to a function that then makes a second request to the same webserver using download.file(). This second requests gets queued by httpuv to be served when the first one completes, but obviously that never happens because download.file() just keeps waiting, until it times out.

    This does not happen in the cloud server because apache2 is multi threaded.

    To make it work with the single user server, you can make the first function save the data as an object in the workspace, and then the second function can access it via the session key. Or alternatively you could save it on disk or in a database or something, where the second function can access it. Anything that doesn't need a second http connection to the same local server.