Concurrency and background tasks in Grails
Join the DZone community and get the full member experience.
Join For FreeCan web applications benefit from concurrent programming? Should web developers know how to make multiple threads behave and cooperate safely?
If you've ever shared data across concurrent HTTP requests, jugled cooperating AJAX calls or simply needed to reduce request latency by parallelizing work on big chunks of database data, chances are high your answer to both questions will be a big YES. Concurrent programming is definitely becoming relevant to web applications.
Concurrent Grails
Now, imagine you work on a Grails application and have a set of expensive calculations you want to run asynchronously in the background. Or perhaps processing sequentially a collection of images uploaded by the user takes too much time and you got an idea to leverage the multi-core chips on your servers to shorten the latency by parallelizing the job. Or multiple web services need to be contacted as part of the request handling and you feel like doing it in parallel can't hurt. Or, .., well you name it. The list may go on for quite a while.
Grails is famous for giving programmers a variety of options in all essential domains like security, persistence or presentation. When it comes to concurrency, there are also multiple options available for you to pick from.
Without any extra work just use the well-known Java 5 concurrency classes. Or check out the proposed JSR-166y library giving you handy abstractions for Fork/Join and Parallel Array. You might also consider the Background thread Grails plugin or leverage the polyglot nature of Grails and do you concurrent stuff in other languages, such as Clojure.
Sticking to Groovy
But wait, isn't there a pure Groovy solution available? Could GPars, a Groovy based and Groovy targeted concurrency library, help you in Grails?
Certainly it can. GPars aims to bring high-level concurrency concepts, such as actors, agents, parallel collections, dataflow and others to the Groovy programing language. Just add one new dependency in your BuildConfig.groovy file and you're ready to go.
dependencies {
compile 'org.codehaus.gpars:gpars:0.11'
}
It could hardly be easier.
Calculate this in the back room
Starting a calculation in the background is now just a matter of creating or reusing a thread pool and calling the desired closure asynchronously in any of your controllers, services or wherever you need.
Closure myExpensiveCalculation = {...}
withPool {
Future result = myExpensiveCalculation.callAsync()
}
You can use the returned Future instance to query the calculation status, get the result or cancel it any time.
Everyone gets a task
Frequently you may run into situations when you need to process a collection of elements (data rows, files, images, entities, services, etc.). Doing it concurrently is just a matter of adding Parallel to the ordinary Groovy collection method names.
def favoriteQuote = [lufthansa, ba, airfrance, delta]
.collectParallel{it.askForQuote myTrip}
.findAllParallel{it.serveVeganFood()}
.minParallel{it.price}
Don't touch my shopping cart
What if you need some in-memory data to be shared across requests of multiple users? A cache could be a good example. You have to handle potentially concurrent requests arriving and hitting your data, ensure updates get propagated among threads correctly and the data doesn't get corrupt along the way. Similarly care needs to be taken when you share data among potentially concurrent requests of a single user (AJAX anyone?).
Wrapping the piece of data in an Agent would nicely solve the issues in many possible scenarios.
def bookToBuy = Book.findBookByName('Griffon in Action')
def cartAgent = session['cart']
cartAgent << {Cart cart ->
if (!cart.contains bookToBuy) {
cart.add bookToBuy
}
}
The agent will serialize access to the actual shopping cart and so in our sample code, no matter how nervous you are when clicking the Buy button, you correctly end up with only one piece of the desired book in the cart.
Actors, dataflow, fork/join and more
You may now consider walking the 3 minute Groovy Fast Track to get a better grasp of GPars. Concurrency is very addictive when done at a higher level of abstraction. Once you start you'll want more. Keep coming to the GPars User Guide for your regular doses. Learn about actors, check out dataflow and experiment with Fork/Join.
And most of all, enjoy concurrency in Grails!
Opinions expressed by DZone contributors are their own.
Trending
-
Playwright JavaScript Tutorial: A Complete Guide
-
Building A Log Analytics Solution 10 Times More Cost-Effective Than Elasticsearch
-
Build a Simple Chat Server With gRPC in .Net Core
-
Front-End: Cache Strategies You Should Know
Comments