This is a Heroku Buildpack for applications which use R for statistical computing and CRAN for R packages.
The buildpack supports the heroku-18 and heroku-20 stacks.
It also includes support for the Packrat and renv package managers, and the Shiny and Plumber web application frameworks.
The buildpack URL is https://github.com/virtualstaticvoid/heroku-buildpack-r.git
. Provide it when creating your application on Heroku as follows:
heroku create --buildpack https://github.com/virtualstaticvoid/heroku-buildpack-r.git
The buildpack will detect your application makes use of R if it has one (or more) of the following files in the project directory:
init.R
packrat/init/R
renv/activate.R
run.R
app.R
plumber.R
If the init.R
file is provided, it will be executed in order to install any R packages, and if packrat/init.R
or renv/activate.R
files are found, the respective package manager will be bootstrapped and packages installed.
Additionally:
- If the
run.R
file is provided, the buildpack will be configured as a Shiny application. - If the
plumber.R
file is provided, the buildpack will be configured as a Plumber application.
See the detect script for the matching logic used.
The init.R
file is used to install R packages as required.
NOTE: Using either Packrat or renv are a better way to manage your package dependencies and their respective versions, so the init.R
file isn't required if you use packrat
or renv
.
The following example init.R
file can be used. Provide the package names you want to install to the my_packages
list variable:
# init.R
#
# Example R code to install packages if not already installed
#
my_packages = c("package_name_1", "package_name_2", ...)
install_if_missing = function(p) {
if (p %in% rownames(installed.packages()) == FALSE) {
install.packages(p)
}
}
invisible(sapply(my_packages, install_if_missing))
R packages can also be installed by providing a .tar.gz
package archive file, if a specific version is required, or
it is not a publicly published package. See local-packages for an example.
# init.R
#
# Example R program to installed package from local path
#
install.packages("PackageName-Version.tar.gz", repos=NULL, type="source")
NOTE: The path to the package archive should be a relative path to the project root directory, so that it works locally in development and during deployment on Heroku.
For convenience, a R helper function, helpers.installPackages
, is included by the buildpack to make installing packages easier.
Thus the init.R
file can be reduced to a single line of R code as shown. Provide the package names you want to install as arguments to the helper:
helpers.installPackages("package_name_1", "package_name_2", ...)
This version of the buildpack still supports the use of an Aptfile
for installing additional system packages, however this functionality is going to be deprecated in future as it isn't a foolproof solution.
It is based on the same technique as used by the heroku-buildpack-apt buildpack to install Ubuntu packages using apt-get
.
There are various technical and security reasons why it is no longer recommended, so your mileage may vary.
If any of your R packages dependend on system libraries which aren't included by Heroku, such as libgmp
, libgomp
, libgdal
, libgeos
and libgsl
, you should use the Heroku container stack together with heroku-docker-r instead.
To maually download, build, and install binary dependencies (Linunx apt-get libraries, etc.) you can modify compile and provide the url to download the file for building.
Copy the example script in the "compile" file to add any additional libraries to your Heroku enviornment.
Example
echo "-----> Starting fftw compilation"
echo "Downloading http://www.fftw.org/fftw-3.3.10.tar.gz" | indent
wget --quiet http://www.fftw.org/fftw-3.3.10.tar.gz
echo "Unpacking fftw" | indent
tar -xf fftw-3.3.10.tar.gz
cd fftw-3.3.10
echo "Running configure" | indent
./configure --prefix="$BUILD_DIR" >/dev/null 2>&1
echo "Running make with target install" | indent
make install >/dev/null 2>&1
echo "Running make with target distclean" | indent
make distclean > /dev/null 2>&1
You can run the R console application as follows:
$ heroku run R ...
Type q()
to exit the console when you are finished.
You can also run the Rscript
utility as follows:
$ heroku run Rscript ...
Note that the Heroku slug is read-only, so any changes you make during the session will be lost.
Shiny applications must provide a run.R
file, and can also include an init.R
in order to install additional R packages.
The Shiny package does not need to be installed, as it is included in the buildpack already.
The run.R
file should contain at least the following code, in order to run the web application.
Notice the use of the PORT
environment variable, provided by Heroku, which is used to configure Shiny and the host must be 0.0.0.0
.
# run.R
library(shiny)
port <- Sys.getenv('PORT')
shiny::runApp(
appDir = getwd(),
host = '0.0.0.0',
port = as.numeric(port)
)
See the virtualstaticvoid/heroku-shiny-app example application.
Plumber applications must provide an app.R
file, but can also include an init.R
in order to install additional R packages.
The Plumber package does not need to be installed, as it is included in the buildpack already.
The app.R
file should contain at least the following code, in order to run the web application.
Notice the use of the PORT
environment variable, provided by Heroku, which is used to configure Shiny and the host must be 0.0.0.0
.
# app.R
library(plumber)
port <- Sys.getenv('PORT')
server <- plumb("plumber.R")
server$run(
host = '0.0.0.0',
port = as.numeric(port)
)
See the virtualstaticvoid/heroku-plumber-app example application.
You can use the Heroku scheduler to schedule a recurring R process.
An example command for the scheduler to run prog.R
, would be R --file=prog.R --gui-none --no-save
.
The buildpack currently supports R 4.0.0
. This is updated periodically when new versions of R are released.
This version of the buildpack still uses a fakechroot during slug compilation, to compile R packages which may include C or Fortran code.
However it no longer uses the chroot
at runtime so it can work better in scenarios where other language buildpacks are used, such as with Python, Ruby or Java, and so that the slug size is greatly reduced.
If you are migrating to this version of the buildpack, you no longer need to prefix commands to use fakechroot
, fakeroot
or chroot
.
Wrappers of these commands are included and they will output warning messages to alert you of their use.
The binaries used by the buildpack are hosted on AWS S3 at https://heroku-buildpack-r.s3.amazonaws.com.
See the heroku-buildpack-r-build2 repository for building the buildpack binaries yourself.
The buildpack includes the following default process types:
console
: Executes theR
terminal application, which is typically used for debugging.web
: Executesrun.R
to run Shiny or Plumber applications.
The R
and Rscript
executables are available like any other executable, via the heroku run
command.
You can include a Procfile in your project if you want to override the default process types and/or their command lines. This is typically required if you are using multiple buildpacks.
For example, the following Profile defines the commands for the web
and console
processes.
web: R --file=myprogram.R --gui-none --no-save
console: R --no-save
You can include the heroku.yml
build manifest in you project if you want to override the default process types and/or their command lines, within the run
section. This is typically required if you are using multiple buildpacks.
For example, the following heroku.yml
file defines the commands for the web
and console
processes.
run:
web: R --file=myprogram.R --gui-none --no-save
console: R --no-save
Where possible, always use relative paths for files, so that your application is more portable; so that it can run locally in development and at runtime on Heroku without any differences.
The current directory on Heroku will always be /app
and your application will be installed to this directory, so relative paths should be in respect of the root directory of your project.
If you need to use absolute paths, consider using getwd()
together with file.path()
to build up the path instead of hardcoding them.
You can include an .Rprofile
in your application's root directory and it will be executed at the start of any R process.
It can be used as a convenient way to bootstrap your application, sourcing common utilities or performing configuration tasks.
Please do not use it to install R packages, since it may cause problems during deployment (slug compilation) and will fail at runtime.
It is possible to override the default CRAN mirror used, by providing the URL via the CRAN_MIRROR
environment variable.
E.g. Override the URL by setting the variable as follows.
heroku config:set CRAN_MIRROR=https://cloud.r-project.org/
Check the CRAN mirror status page to ensure the mirror is available.
To improve the time it takes to deploy the buildpack caches the R binaries and installed R packages.
If you need to purge the cache, it is possible by using heroku-repo CLI plugin via the heroku repo:purge_cache
command.
See the purge-cache documentation for more information.
- Original inspiration from Noah Lorang's Rook on Heroku project.
- Script snippets from the rstudio/r-builds project.
- Tests from the rstudio/r-docker project.
- fakechroot library.
- tcl/tk library.
MIT License. Copyright (c) 2020 Chris Stefano. See LICENSE for details.