```{r echo = FALSE} options(markdown.HTML.options = "toc") ``` # Deployment with FastRWeb ## Deploying AnalysisPageServer applications with Rserve/FastRWeb System It is possible to deploy `AnalysisPageServer` applications using the Rserve/FastRWeb system. Unlike the Rook/Rhttpd combination, this environment properly handles concurrent requests and is expected to be more stable. The installation and setup should be easier than Apache/RApache. My own production systems have been based on Apache/RApache and so I have less experience trying to scale under `Rserve`/`FastRWeb`, but it looks like it could be a good solution, and I definitely recommend it over the Rook/Rhttpd option. This document will take you through steps for deployment in this environment. ## What are Rserve and FastRWeb? From their websites: > Rserve is a TCP/IP server which allows other programs to use facilities of R from various languages without the need to initialize R or link against R library. > FastRWeb is an infrastructure that allows any webserver to use R scripts for generating content on the fly, such as web pages or graphics. `Rserve` is really the server software. However, it has a lower-level interface than `FastRWeb`. Also, the direct HTTP connections that `Rserve` supports are still considered experimental. `FastRWeb`, at least in the way we are going to use it, consists of a CGI executable which sends HTTP requests via the socket to the `Rserve` process. It also has some functionality to help with some of the lower-level HTTP-related tasks like creating HTTP responses within R. More recent versions of `Rserve` do have the capability of communicating over HTTP, which means that it should be possible to deploy `AnalysisPageServer` with just the `Rserve` layer and without `FastRWeb`. I have not yet tried this, and am not describing that process in this document. ## Install Rserve and FastRWeb Rserve and FastRWeb are both available through rforge. You may be able to install them with ```{r eval = FALSE} install.packages(c('Rserve','FastRWeb'),,'http://www.rforge.net/') ``` You may need to add the switch `type="source"` to this. If you get an error installing the Cairo dependency you may be able to work around this by installing the binary version rather than the source. If you are using a version of R for which there is not a binary available, you can force the installation by downloading the correct binary package for your OS from the [Cairo CRAN page](http://cran.r-project.org/web/packages/Cairo/index.html), then installing from the command line with something like `R CMD INSTALL /path/to/downloaded/tarball/Cairo_99.9.9.tgz`. Then go back and try again to install `FastRweb`. After you install `FastRWeb` you have to set up a `FastRWeb` environment. See the [documentation for that package](http://svn.rforge.net/FastRWeb/trunk/INSTALL) for more information. This is typically accomplished by running the `install.sh` script that comes with the package, which sets up the `/var/FastRWeb` directory for you: ```{r eval = FALSE} system(paste("cd",system.file(package="FastRWeb"),"&& install.sh")) ``` Among other things, this will create a configuration file in `/var/FastRWeb/code/rserve.conf`. You'll have to make one modification to this file. The default looks like this: ``` socket /var/FastRWeb/socket sockmod 0666 source /var/FastRWeb/code/rserve.R control enable ``` ***IMPORTANT!!!*** In the last line change `control enable` to `control disable`. This change is essential as the control commands prevent `Rserve` from handling parallel connections correctly, and your server will crash. That will give you this configuration: ``` socket /var/FastRWeb/socket sockmod 0666 source /var/FastRWeb/code/rserve.R control disable ``` After making this modification, you should work through the rest of the FastRWeb INSTALL document to complete the installation and start your `FastRWeb`-configured `Rserve` server. ## Developing your FastRWeb Application ```{r landing-page, echo = FALSE} f <- formals(AnalysisPageServer::new.FastRWeb.analysis.page.run) unslash <- function(x) sub("/+$", "", sub("^/+", "", x)) landingPageURL <- file.path("http://localhost", unslash(f$FastRWeb.prefix), "APS", unslash(f$front.end.location), "analysis-page-server.html") ``` In the default configuration, `FastRWeb` maps URLs to scripts in the directory `/var/FastRWeb/web.R/`. You can deploy as many AnalysisPageServer applications as you want by creating multiple files in that directory. Here we'll just create one, called `APS.R`. With default configuration your server would then be located at `r landingPageURL` URL. The content of a `FastRWeb` script is a bit of code which will get evaluated each time a request is made. At some point in the script a function must be assigned to the top-level variable `run`. In some ways the `run` function is similar to `AnalysisPageServer`'s idea of what an `AnalysisPage` handler is. Each of the parameters of the HTTP query string are parsed and sent as arguments to the `run` function, and the `run` function then results what is called a `FastRWeb` object, which somehow represents the response. If you are working in the `AnalysisPageServer` framework you don't have to worry about most of these details. You just build your `AnalysisPageRegistry` and then call the `new.FastRWeb.analysis.page.run()` function, assigning the result (which is itself a function) to the `run` variable. The following would constitute a `FastRWeb` script for an application containing the volano plot from the Interactive Applications vignette. Everything but the last line is copied verbatim from that vignette. ```{r eval = FALSE} library(AnalysisPageServer) x <- rep(1:nrow(volcano), each = ncol(volcano)) y <- rep(1:ncol(volcano), nrow(volcano)) volcano.cells <- data.frame(x = x, y = y, Height = as.vector(t(volcano))) volcano.handler <- function(color1 = "red", color2 = "blue") { par(mar = c(1, 1, 4, 1)) chosen.colors <- c(color1, color2) col <- colorRampPalette(chosen.colors)(50) image(datasets::volcano, xaxt = "n", yaxt = "n", main = "Maunga Whau Volcano", col = col, cex.main = 2) return(volcano.cells) } volcano.page <- new.analysis.page(handler = volcano.handler, name = "volcano", description = "Draw the Maunga Whau Volcano in Two Colors") reg <- new.registry(volcano.page) run <- new.FastRWeb.analysis.page.run(reg, FastRWeb.scriptname = "APS") ``` `new.FastRWeb.analysis.page.run` has other other options which are useful if you have non-default `FastRWeb` configuration. In particular, if your FastRWeb CGI driver is not located at `/cgi-bin/R` then you would have to specify that. See that function's inline documentation for that information. In any case `FastRWeb.scriptname` is required, and it has to be the same as the name of the `FastRWeb` script from which the app will be server, without the `.R` suffix. Once you put that in the file `/var/FastRWeb/web.R/APS.R` you can then point your browser to the landing page `r landingPageURL`. ## Deploying your FastRWeb/Rserve Application One of the nice things about developing in this environment is that the script is reprocessed on each page load. This includes any libraries you load, which means that if you develop your `AnalysisPageServer` within an R package (as you should, if you really mean business), then you can just install a modified version of that R package and refresh your browser, and the modification will be re-loaded. The downside of this system is that you pay the cost of page load on each request. This can be significant, especially since the front end requires multiple AJAX callbacks to the server in order to load the application and make even one plot. Even static files are handled this way and would trigger loading of any packages with `library()` calls in your script. However, it is possible for you to have your cake and eat it, too. Once you are done development you can move the code to the startup script in `/var/FastRWeb/code/rserve.R`. At the bottom of that script you could have something like this: ```{r eval = FALSE} library(MyAPSPackage) myRun <- new.FastRWeb.analysis.page.run(myAPSRegistry(), FastRWeb.scriptname = "APS") ``` Then, in `/var/FastRWeb/web.R/APS.R` all you put is this: ```{r eval = FALSE} run <- myRun ``` This time you *do* have to restart the `Rserve` server, which I usually do like this: ```{r eval = FALSE} killall Rserve /var/FastRWeb/code/start ``` Then your server is poised to handle the requests much more quickly since it will have everything it needs already built in memory. If you are trying to just run through the example in this document and don't have your own app packaged nicely into `MyAPSPackage`, you can just copy this whole long thing into `/var/FastRWeb/code/rserve.R`: ```{r eval = FALSE} library(AnalysisPageServer) x <- rep(1:nrow(volcano), each = ncol(volcano)) y <- rep(1:ncol(volcano), nrow(volcano)) volcano.cells <- data.frame(x = x, y = y, Height = as.vector(t(volcano))) volcano.handler <- function(color1 = "red", color2 = "blue") { par(mar = c(1, 1, 4, 1)) chosen.colors <- c(color1, color2) col <- colorRampPalette(chosen.colors)(50) image(datasets::volcano, xaxt = "n", yaxt = "n", main = "Maunga Whau Volcano", col = col, cex.main = 2) return(volcano.cells) } volcano.page <- new.analysis.page(handler = volcano.handler, name = "volcano", description = "Draw the Maunga Whau Volcano in Two Colors") reg <- new.registry(volcano.page) run <- new.FastRWeb.analysis.page.run(reg, FastRWeb.scriptname = "APS") ``` The landing page would then be available at this URL: [http://localhost/cgi-bin/R/APS/dist-aps/analysis-page-server.html](http://localhost/cgi-bin/R/APS/dist-aps/analysis-page-server.html)