Skip to content

Aspectos a considerar para graficar con R 3.6.1 en un aplicación rails 6.x corriendo en adJ 6.6

Vladimir Támara Patiño edited this page Oct 4, 2021 · 26 revisions

1. R

En R se llama librería a un directorio donde se ponene paquetes para R (ver [R-Admin])

En R el espacio de trabajo es el directorio desde el cual se inicia R. Ese directorio será el que le de contexto a R pues allí se almacenan: .RData con los datos de la sesión y .Rhistory con el historial de ordenes. La motivación es un directorio por análisis, donde digamos se almacene un objeto x cuyo significado es claro en el contexto del análisis que se hace (ver [R-Intro]).

Aunque el porte de R a OpenBSD es relativamente reciente (desde OpenBSD 5.8), hemos experimentado pocas fallas (Una con readr y otra con later) y en tales casos hemos encontrado una comunidad de usuarios de OpenBSD más o menos activa.

2. Gema rinruby

Cuando se usa desde una aplicación en rails, inicia R desde el mismo directorio principal de la aplicación. Sólo con incluirla en Gemfile cuando la aplicación Rails inicie, iniciará una instancia de R, que puede usarse con ::R.eval.

3. shiny

Al lado del cliente usa jquery y bootstrap 3 (lamentamos que no use bootstrap 4 ni Javascript modular reciente). Para comunicación entre cliente y servidor usa websockets.

Es loable que puede atender diversas conexiones simultanamente y que planea una esquema de escalamiento masivo, según el video [shiny-tutotrial] hacía el minuto 88, donde se representa el modelo de ejecución planeado para shiny:

  • La misma aplicación podría correr en varios servidores,
  • cada servidor podría correr diversas instancias de R con la aplicación shiny.
  • Una instancia de R con la aplicación shiny podría atender a varios usuarios

Se escalaría a una instancia más de R con aplicación cuando empiece a responder lentamente, y se escalaría a otro servidor cuando las instancias de R agoten recursos de un servidor. En cuanto a implementación, al momento de este escrito, la gente de Rstudio parece que soporta hasta tener varias instancias de R en mismo servidor (i.e escalar aplicaciones sobre múltiples procesos R) con el producto comercial RStudio Connect, que daría más posibilidades que shiniyapps.io (incluyendo procesos de R persistentes para lograr tiempos de carga más rápido) según https://rstudio.com/products/shiny/shiny-server/, aunque no hay soporte para shiny-server fuera de Linux. La implementación de shiny-server (https://github.com/rstudio/shiny-server/), inicia desde un ejecutable del sistema una aplicación node.js sobre express que por cada cliente inicia una instancia de R. Dedica buenas líneas a mantener bitácoras que puedan dar cuenta del uso de memoria y recursos del servidor.

A la hora de ejecución notamos que shiny bloquea al proceso R en el que corre por completo hasta que se cierra la aplicación, en particular con Control-C, desde el servidor, o, desde la aplicación shiny con stopApp() (como se indica en https://stackoverflow.com/questions/32529215/close-a-shiny-app-on-a-click )

4. Aplicación rails que corre una apliación shiny/R con rinruby

Tuvimos problemas con el paquete later porque sus fuentes dependen de un mal uso de los estándares c++11 y c++17, ver https://github.com/r-lib/later/pull/121

Tuvimos problemas para instalar el paquete readr, el problema estaba resuelto en github. Pero la de github requiere gemas recientes, así que en adJ 6.6 consideramos mejor orden para preparar un ambiente usable:

  • Instalar paquete R en adJ:
doas pkg_add R
  • Desde el directorio de aplicación ejecutar R e instalar los paquetes knitr, Rcpp, rlang, BH confirmar el uso de una librería en directorio personal y puede ser en el directorio por omisión. Hemos usado con éxito el repositorio que mantiene la Icesi en Cali. La sesión luce así:
$ R
...
> install.packages(c('knitr', 'Rcpp', 'rlang', 'BH'))
Warning in install.packages(c('knitr', 'Rcpp', 'rlang', 'BH')) :
  'lib = "/usr/local/lib/R/library"' is not writable
Would you like to use a personal library instead? (yes/No/cancel) yes
Would you like to create a personal library~/R/x86_64-unknown-openbsd6.6-library/3.6to install packages into? (yes/No/cancel) yes
--- Please select a CRAN mirror for use in this session ---
Secure CRAN mirrors
 1: 0-Cloud [https]  
...
18: Colombia (Cali) [https]
...
Selection: 18
...
* DONE (knitr)

The downloaded source packages are in/tmp/Rtmpr09eRC/downloaded_packages> q()
Save workspace image? [y/n/c]: y
  • Instalar en R paquete later, pero el modificado para OpenBSD/adJ mientras se acepta/mejora parche para versión oficial (ver https://github.com/r-lib/later/pull/121 ). Sería más fácil instalarlo con el paquete devtools pero ese depende de later así que debe hacerse manualmente:
mkdir -p ~/comp/R
cd ~/comp/R
git clone -b fix-cxx17 git@github.com:vtamara/later
R CMD INSTALL later
  • Volver al directorio de la aplicación, instalar el paquete libgit2 con doas pkg_add libgit2 y desde R instalar devtools y de github un paquete reciente readr.
install.packages("devtools")
devtools::install_github("tidyverse/readr")

Si readr en su versión más reciente presenta problemas, puede intentar:

devtools::install_github("tidyverse/readr@ec0d898992359389dce5e565e2591463baf18adc")
  • Instalar shiny y otros paquetes
install.packages("shiny")
  • Como una aplicación shiny bloquea a R mientras se ejecuta, este a su vez bloquea a rinruby y a la aplicación rails. Se ha experimentado con éxito iniciar R y la aplicación shiny desde un proceso bifurcado con fork
  • Sin embargo hemos notado que al agregar rinruby en el Gemfile de una aplicación rails, al iniciar la aplicación rails, automaticamente se inicia una instancia de R, que es la que se usará cuando se ejecute ::R.eval (bloqueando aplicación rails si se usa shiny). Inculso tuvimos problema de bloqueo usando RinRuby.new.eval.
  • Lo que nos ha funcionado es detener el proceso R (no se logró con kill), pero desde la aplicación rails con:
::R.quit

e iniciar una nueva sesión dentro del proceso bifurcado con:

miR = RinRuby.new
miR.eval "codigo R...."
  • La aplicación shiny empieza a escuchar en el servidor en un puerto que se especifique.

5. Proxy para servir websockets

shiny emplea websockets para mantener una comunicación fluida entre cliente y servidor. Como se explica en [nginx-ws] por ser un protocolo que puede operar sobre HTTP pero con una actualización, puede requerir un proxy para websocket si el servidor está detras de un cortafuegos.

Nginx podría usarse, adaptando ejemplos de [nginx-ws] y [nginx-wss] para el caso de una conexión en el servidor sin cifrar, pero cifrada en el proxy/cortafuegos:

    map $http_upgrade $connection_upgrade {
            default upgrade;
            '' close;
    }

    upstream websocket {
            server 192.168.77.78:2902;
    }

    server {
            server_name defensor.info;
            listen 2902 ssl;
            ssl_certificate /etc/ssl/defensor-cadena.info.crt;
            ssl_certificate_key /etc/ssl/private/defensor.info.key;
            error_log logs/d2902-error.log;
            location "/" {
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_pass http://websocket;
                    proxy_http_version 1.1;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header Connection $connection_upgrade;
                    proxy_set_header Host $host;
            }
    }

6. Dificultades

  • R y sus librerías son muy hetereogeneas. Muchas operaciones requieren librerías de terceros, no está centralizada la documentación. Aunque toda función de R y toda librería cuenta con documentación en ocasiones la documentación oficial es insuficiente (muy en concreto ggplot donde es todo un reto encontrar como hacer una gráfica de líneas).
  • shiny después de algunos minutos de actividad se pone gris y bloquea. Solo recargando continua
  • shiny usa bootstrap 3 y jquery aunque las aplicaciones de Pasos de Jesús usan bootstrap 4 y buscamos transito a librerías más recientes de Javascript que aprovechen el sistema de módulos de Javascript.
  • El control para selección múltiple de shiny no es estándar y sólo puede manejarse con flechas y borrando.
  • No es trivial sincronizar la ejecución de la aplicación shiny con la de rails, el mejor método que hemos encontrado es relanzando proceso R con aplicación shiny cuando se detecta que no responde información correcta por http o cuando se detecta que no está en el grupo de procesos del proceo de ruby. Hemos notado que no es muy robusto, y en ocasiones no se detiene el proceso R cuando se detiene la aplicación rails, que hemos observado es especialmente frecuente en sitios de producción con unicorn y nginx.
  • También hemos notado que en ocasiones el proceso en R se detiene o al menos no responde a la aplicación shiny. Aún nos falta poder detectar esta situación para que el usuario pueda ver la gráfica. En ocasiones presenta un pantallazo como el siguiente:

Erorr esporádico en aplicación shiny

  • Resolver en el paquete later el problema de su mal uso de los estándares C++11 y C++17 ha sido complejo en cuanto a interacción con sus desarrolladores, ver https://github.com/r-lib/later/pull/121

7. Bibliografía