Grails has had support for asynchronous programming for some time now but it seems to have become more well-defined in Grails 3. It has Promises, Events, and even asynchronous processing in GORM. The article is focusing on some functionality in Event processing, most of the functionality coming from Reactor.
You can see my simple example on Github. It’s pretty straightforward on how it works — you enter a number into a form, and then check the server output for counting from 1 to that number. The numbers won’t be in order though — that is because a service is sending them to another service in an asynchronous manner.
The LoopService
is really what starts this off — it gets a number and starts the loop:
package grails3.event.driven
import grails.transaction.Transactional
class LoopService {
def count(int limit) {
(1..limit).each {
notify( "int.echo",it as Integer)
}
}
}
Note that it doesn’t call another service directly — instead it calls this magic notify
method that takes a string and the value. This is because services in Grails 3 have the Event
trait which give you an interface into Reactor. The string is the name of the event to fire and the second parameter is the Object to send to the consumer of the event. Notice that I said Object… I first used type int
to make this example and it took me awhile to figure out why I had a NullPointerExeception
. Simply moving it to Integer
made it start working.
The consumer of this event is the EchoNumberService
.
package grails3.event.driven
import reactor.spring.context.annotation.*
@Consumer
class EchoNumberService {
@Selector('int.echo')
void echo(Integer i) {
println "##### number id ${i}"
}
}
The Consumer
and Selector
annotations come from Reactor. Consumer
simply signifies that this class consumes events and Selector
lets you give the name of the event that method consumes. Note that the echo
method consumes the int.echo
event we used above. I think the other important thing to note is that there is nothing else do to! There is nothing in the method itself that signifies that it’s running in an asynchronous matter. And you could use the same method in a synchronous scenario if need be by calling the method directly.
Changing Hibernate mappings in a Grails application
Groovy will compile just fine in certain scenarios where no arguments are passed to a method that expects one.
Mike has almost 20 years of experience in technology. He started in networking and Unix administration, and grew into technical support and QA testing. But he has always done some development on the side and decided a few years ago to pursue it full-time. His history of working with users gives Mike a unique perspective on writing software.