Shiny Now Supports Async Execution

Nan Xiao 2018-05-21 2 minute read

Shiny is my favorite web application framework. It is simply awesome. Shiny 1.1.0 was released to CRAN last week. This update brings probably the most significant feature/improvement in recent years: async execution support. With the help of future, promises (computer science people surely knew how to name abstract things…), and this shiny update, you can now write scalable web applications using Shiny.

You Want It When? (Zootopia)

You Want It When? (Zootopia)

In brief, if you have some long-running computations (such as querying a remote database, live fitting a statistical model) in your Shiny app, that computation would block additional users to use the app simultaneously, until that computation is finished. This is partially due to R’s single-threaded nature. Even if you could use multiple processes to serve a single app (such as using Shiny Server Pro or ShinyProxy), these synchronous executions will still severely limit the scalability of your app, since multiple users could still end up with using the same process when the number of concurrent users is significant.

By executing these computations asynchronously, you can avoid such issues as much as possible. Conceptually, this means running these time-consuming computations in separate R processes (which do not block new users), and handle the returned values automatically, no matter if they are successful or not. It sounds simple enough but could be complex to implement rigorously. Luckily, we don’t need to worry about the low-level details here. We only need to make two specific changes in the server logic to have such asynchronous executions (by using future and promises):

  1. Wrap the long-running computation with future() or future({});
  2. After the future object, chain the following computations using the promises pipe operator %...>% instead of the magrittr pipe operator %>%, to get the object to render.

In reality, it might be a bit more complicated than this, since you might want to modify some of your previous R code before you can chain them using the pipe operator, but in principle, this should work.

In summary, the new async execution support in Shiny could potentially help eliminate the previous performance bottlenecks and scale up some of your apps substantially, especially if you want to create enterprise-grade web applications. I would recommend watching Joe Cheng’s introductory talk video to have a general idea and this vignette explaining the technical details on how to appropriately modify your app to achieve this.