openanalytics / shinyproxy

ShinyProxy - Open Source Enterprise Deployment for Shiny and data science apps
https://www.shinyproxy.io
Apache License 2.0
523 stars 152 forks source link

Feature Request: Reload application.yml Dynamically #456

Open jubilee2 opened 1 year ago

jubilee2 commented 1 year ago

Feature Request

One of the features that we are considering for the future is the ability to reload the application.yml file without restarting ShinyProxy. This would allow us to update the image version of sub Shiny apps or edit user permissions for individual apps dynamically. We are thinking of implementing this feature either through a web UI or an API trigger.

Expected Behavior

We would like the ability to make changes to the application.yml configuration file, such as updating image versions or modifying user permissions, without the need to restart ShinyProxy. This would provide greater flexibility and reduce downtime when managing and updating Shiny apps.

Use Case

Implementation Options

We are considering implementing this feature through one of the following methods:

  1. Web UI: Provide a user-friendly web interface within ShinyProxy where administrators can make configuration changes and trigger a reload of the application.yml file.

  2. API Trigger: Implement an API endpoint that allows administrators to send a request to reload the configuration dynamically.

danielloader commented 12 months ago

This comes into its own when the application.yml is mounted into a pod on kubernetes as a secret or configmap, as changes to those mounted entities have an eventually consistent model of propagating those changes down.

NOTE: Though you'd need to make the path to the application config file configurable if it's not already, as you'd need to volume mount a directory path not a subPath to a single file for this propagation to happen.

LEDfan commented 9 months ago

Hi

In general we have taken the approach of only reading the configuration file at startup of ShinyProxy and not re-loading any of the configuration settings. The main reason is that certain aspects of the configuration are managed by Spring (Boot) which will cause certain services to be loaded and initialized while other parts of the code may not be started. Changing this at runtime, would be very complex. In addition, this allows caching certain values in memory, while not having complex logic to invalid these caches.

However, since ShinyProxy 3.0.0, the currently running proxies no longer need access to the proxyspec configuration. That means that the running proxies are completely independent of the ShinyProxy configuration. E.g. when using the ShinyProxy operator, it is possible to remove a spec while still keeping the proxies using this spec. With this change, it would be easier to only re-load the specs without restarting ShinyProxy. The difficulty here would be to check which caches inside ShinyProxy would need to be refreshed.

To conclude, I think this is technically possible, but currently we do not have plans to implement this. Therefore, I'll keep this issue open as a feature request.

corey-dawson commented 5 months ago

I will add, using kubernetes, i create the application.yml file as a configmap and mount it into the deployment. To ensure shinyproxy restarts, I add an ENV variable with the git commit number. Therefore, every push with yaml changes ensures the deployment will restart because of the new commit sha. Helm, a template manager and ARGO a continuous deployment application make this really streamlined

LEDfan commented 5 months ago

Hi @corey-dawson on Kubernetes you can also use the shinyproxy operator: https://github.com/openanalytics/shinyproxy-operator . This works in a similar way as you described. However, it will keep the old ShinyProxy servers running, until they have no active websocket connections. This ensures that the websocket connection isn't terminated (and therefore state is lost) when using e.g. Shiny apps,

ggarza31416 commented 1 month ago

Hey @corey-dawson, could you share how you achieved to mount application.yml file as a configmap ? I am trying to do the same but I having a lot of troubles to make it work.

corey-dawson commented 3 weeks ago

Hey @corey-dawson, could you share how you achieved to mount application.yml file as a configmap ? I am trying to do the same but I having a lot of troubles to make it work.

@ggarza31416 Sure. Achieve a config map mount without helm. Just the skeleton, but it is important to specify the volume/volumeMounts correctly. In addition, notice the key in the configmap is "application.yml" to prepare for this data to be saved as a file.

configmap.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: shinyproxy-setup
  namespace: mynamespace
  labels:
    app: my-shinyproxy
data:
  instance: dev
  application.yml: |
    proxy:
      title: Open Analytics Shiny Proxy
      logo-url: https://www.openanalytics.eu/shinyproxy/logo.png
      landing-page: /
      heartbeat-rate: 10000
      heartbeat-timeout: 60000
      port: 8080
      authentication: simple
      admin-groups: scientists
      # Example: 'simple' authentication configuration
      users:
        - name: jack
          password: password
          groups: scientists
        - name: jeff
          password: password
          groups: mathematicians
      specs:
        - id: 01_hello
          display-name: Hello Application
          description: Application which demonstrates the basics of a Shiny app
          container-cmd: [ "R", "-e", "shinyproxy::run_01_hello()" ]
          container-image: openanalytics/shinyproxy-demo
          access-groups: [ scientists, mathematicians ]
        - id: 06_tabsets
          container-cmd: [ "R", "-e", "shinyproxy::run_06_tabsets()" ]
          container-image: openanalytics/shinyproxy-demo
          access-groups: scientists
    logging:
      file:
        name: shinyproxy.log

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: shinyproxy
  labels:
    app: shinyproxy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: shinyproxy
  template:
    metadata:
      labels:
        app: shinyproxy
    spec:
      containers:
      - name: shinypropxy
        image: shinyproxy_image
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: configmap-volume
          mountPath: /opt/shinyproxy/application.yml
          subPath: application.yml
      volumes:
      - name: configmap-volume
        configMap:
          name: shinyproxy-setup
          defaultMode: 420