To demonstrate the design, let’s create a simple R Shiny application. The first step is to click “Service Deployment” from the “Publish” menu.
Creating a New Service
As soon as we create a new service, we have a number of parameters that we can use to build our app. We have parameters for “Git Connection”, “Docker”, and “Resources”.
The first configuration we need to set is our “Git Connection”. Here is where we point our service to the code that it will be running. RStudio hosts a number of example Shiny applications at https://github.com/rstudio/shiny-examples, which we’ll use to test Services.
Since we simply want to download the latest version of these examples, we’ll use the Git branch “master,” which is the convention in Git for the most recent version. We could also use a commit hash or a Git tag here instead of a branch name.
The app we’ll use is found in the folder 001-hello, so we’ll put this as the path of our Git Connection.
The next configuration we need to set is “Docker”. This section configures the Docker image where we’ll be running our code. Docker is an advanced tool for managing dependencies and environments, so it requires a bit of time to learn. There are many nice introductions on the web, and when you’re ready, you can start with this one. Fortunately for our app, Civis has already created a default Docker image for Shiny apps, civisanalytics/civis-services-shiny, so we won’t need to create a custom Docker image to run a Shiny app.
To access Docker images, Services downloads them directly from Docker Hub. “Image Name” is the repository name on Docker Hub and “Tag” is the specific tag or version of the Docker image. Since civisanalytics/civis-services-shiny is the default Docker image for Services, we don’t need to change any Docker parameters.
Finally, we can configure the resources of our app in the Resources section. Here, we can set the amount of memory and compute our app requires and how many replicas to create (in order to serve many users simultaneously), and we can configure whether our app will remain available at all times or will sleep and conserve resources when it’s not being used.
If you are deploying multiple apps, it is a good idea to use as few resources as necessary to ensure that all the apps are speedy and not using up too many compute hours. For our preview, the defaults will work fine, so we don’t need to adjust them.
Now, after entering all of our configuration, we can start our app by clicking "Start Deployment". When you click this button, a preview of the app will load under the preview section of the configuration page.
Viewing a Preview of an App
Once we’re satisfied with how our app looks in Platform, we can edit parameters to optimize the viewing experience for other users. For example, I want to bump up the compute resources and turn on “Specific Times” so my app will be immediately available for users during the work week.
Scheduling an App
Once I make these changes, I click on “View Report”.
Viewing a Service as a Report
Instead of showing us the app on the same page, clicking on "view report" redirects us to a new URL that looks like
This is the live URL for our app! We can share that link with our users and they will immediately be able to access the service. If your users aren’t in your default group, you may need to add them as viewers to the report. This can be done by clicking the share button in the upper right hand corner after minimizing the report.
Sharing a Report with New Users
The final task we need to do now is shut down this deployment so that we’re not using up resources with a service we don’t need. We can navigate back to the Services configuration screen from our report and then stop the deployment from there. We can always turn the service back on later, and all of our configurations will be saved.
Shutting Down a Deployment
Code put in `global.R` or at the top of `app.R` will be run once before the application starts up. Dependencies can be installed by adding a line such as:
- `install.packages(“my_package”) or `devtools::install_github(“my_repo/my_library”)` to one of these files.
- Note: civisanalytics/civis-services-shiny uses a checkpoint version of CRAN, so when using `install.packages` you may not install the latest version of your package from CRAN. Use `devtools::install_github` or specify “repos” in `install.packages` if a certain version is required.
Dependencies from private Github repositories can be installed using devtools if your Civis Platform profile includes Github Credentials.
- If your Service is using the civisanalytics/civis-services-shiny Docker image, your Github credentials are saved as the environment variable GITHUB_PAT instead of REPO_HTTP_TOKEN (the default). This is to comply with devtools.
Common Reasons for Shiny App Greying Out
1) If the Shiny app greys out, this means it has lost its connection to the Shiny server. To make sure your app connection does not time out and that the server reconnects when it does lose connection, you must add the following to your Shiny App:
In your ui.R, reference the keep-alive.js file somewhere in the fluidPage
Add these two lines to your server.R
2) Another reason why the app might grey out is if the Shiny server is busy performing a computation. Shiny performs request handling and all computation in the same thread. This means apps which do a lot of computation block the process from handling additional web requests.
Consider doing these computations in a separate process by wrapping the computationally expensive parts of your app to run in parallel with mclapply or future and increase the CPU resources for your Service (1000 represents 1 core, 2000 represents 2 cores and so on).
3) If your Shiny app greys out immediately after loading, it is probably failing to start. If you have code in
global.R, it executes in between the time that the app "starts" and when the app is active and you see the UI. If the operations in your global.R take a long time, the app can appear to have failed to start, even though Platform says it is still running. There is a one-hour limit on the operations in
global.R, and if your app does not respond to web requests after that point it will be terminated by Platform to save resources.
Scaling & Performance Optimization
Shiny Apps are single-threaded. This means that they can only do one thing at a time, and has a few implications:
- A Shiny App cannot use more than 1000m of CPU by default. Unless you implement some sort of parallel processing, don’t request more than 1000 shares of CPU (which is equivalent to one CPU core).
- We’ve found that the typical, non-optimized Shiny App with 1000m CPU can handle about 7 concurrent users. If you anticipate more than 7 users needing to use your app simultaneously, you may want to increase the number of replicas for your service. Each replica will run independently and will not share state.