Groovy, Reactor, Grails 

& the realtime web
Guillaume Laforge 

@glaforge !

Stéphane Maldini

@smaldini !
Stéphane
Maldini
Consultant and Reactor committer
at
.
!

@smaldini
1
t
r
a
P

Reactor
Reactor — Housekeeping
!

• Tweet questions during the presentation	

– @ProjectReactor
!

• Stop us anywhere if you have a question	

– There are no stupid questions, only stupid answers!

@glaforge — @smaldini / #DV13-rtweb

!4
Reactor — Reactive Architecture ?
REACTIVE
AGILE
EVENT DRIVEN
SCALABLE
AVAILABLE

@glaforge — @smaldini / #DV13-rtweb

!5
Reactor — Reactive Architecture ?
• A good description is available on: 

http://www.reactivemanifesto.org/	

!

• Functional Programming helps as it is stimulus based by nature	

!

• Groovy is a perfect candidate: 

Closures and DSL are first class citizen	

!

• Reactor completes the picture by providing abstractions

@glaforge — @smaldini / #DV13-rtweb

!6
Reactor — Threading model matters
• Context switching hurts performances	

• Locking hurts performances	

• Message passing hurts performances	

• Blocking for a thread hurts performances	

• Creating Threads needs memory

@glaforge — @smaldini / #DV13-rtweb

!7
Reactor — Dealing with performances
• Actors solve the locking and context switching issues 

by becoming state boxes	

• One thread assigned per consumer	

• One thread will ever access a property

• Non Blocking Programming solves thread creation and
waiting issues by delaying logic	

• Callback will be executed when possible (Lazy)	

• Reallocate the blocking time to process something else

@glaforge — @smaldini / #DV13-rtweb

!8
Reactor — LMAX Disruptor and Ring Buffer
• LMAX Disruptor deals with message passing issues	

• Based on a Ring Buffer structure	

• “Mechanical Sympathy” in Disruptor	

!

• http://lmax-exchange.github.com/disruptor/files/
Disruptor-1.0.pdf	

• http://mechanitis.blogspot.co.uk/2011/06/dissecting-disruptorwhats-so-special.html

@glaforge — @smaldini / #DV13-rtweb

!9
Reactor — Disruptor performances

@glaforge — @smaldini / #DV13-rtweb

!10
Reactor — Trisha’s pretty picture of Disruptor
http://mechanitis.blogspot.co.uk/2011/07/dissectingdisruptor-writing-to-ring.html

@glaforge — @smaldini / #DV13-rtweb

!11
Reactor — In love with Disruptor
• Reactor best performances are derived from LMAX Disruptor	

!

• LMAX Disruptor can be considered 

as an evolution of the Actor Model:	

!

• Still avoid locking and deals with context switching	

• Producer/Consumer decoupled	

• Add Pipelining, Batching and more

@glaforge — @smaldini / #DV13-rtweb

!12
Reactor — A foundation part of Spring IO

@glaforge — @smaldini / #DV13-rtweb

!13
Reactor — What is it?
!

• Reactor is a distillation of other libraries and best-practices	

– Elements of other patterns and libraries 

surface throughout Reactor's abstractions	

!

• http://stackoverflow.com/questions/16595393/akka-or-reactor

@glaforge — @smaldini / #DV13-rtweb

!14
Reactor — What can I build with it?
• Reactor applications are reactive	

– Reactive Extensions in .NET	

– Netflix RxJava	

– Observer pattern	

!

• Reactor applications route events based on a Selector	

– Like a routing topic, but can be any object	

– Regex, URI template, Class.isAssingableFrom, custom logic

@glaforge — @smaldini / #DV13-rtweb

!15
Reactor — Landscape

@glaforge — @smaldini / #DV13-rtweb

!16
Reactor — What does it look like?
Create a reactor context
def	
  env	
  =	
  new	
  Environment()	
  
!

Build a reactor
parameter

def	
  reactor	
  =	
  
Reactors.reactor().env(env).dispatcher(RING_BUFFER).get()	
  
!

reactor.on($('topic')){	
  Event<String>	
  ev	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  println	
  "Hello	
  $ev.data"	
  
}	
  

React on ‘topic’ events

!

reactor.notify('topic',	
  Event.wrap('John	
  Doe'))

Trigger reactor ‘topic’ key
@glaforge — @smaldini / #DV13-rtweb

!17
Reactor — Selectors
• Selectors are the left-hand side of an equality comparison	

!

– A Selector can be created from any object using $(obj) 

(or the long form: Selectors.object(obj))	

!

– A Selector can extract data from the matched key	

!

– Predicate<T> Selectors can be created to match on domainspecific criteria like header values

@glaforge — @smaldini / #DV13-rtweb

!18
Reactor — RegexSelector
• A RegexSelector will match a String by executing the regex
over it	

– R(“some.(.*)”)
– Selectors.regex(“some.(.*)”)

@glaforge — @smaldini / #DV13-rtweb

!19
Reactor — RegexSelector
!

• A RegexSelector will match a String 

by executing the regex over it	

!

– R(“some.(.*)”)
!

– Selectors.regex(“some.(.*)”)

@glaforge — @smaldini / #DV13-rtweb

!20
Reactor — RegexSelector
Use a Regex Selector and capture group
reactor.on(R('some.(.+)')){	
  Event<String>	
  ev	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  def	
  s	
  =	
  ev.headers.get('group1')	
  
}	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
s will be ‘topic’
!

reactor.notify('some.topic',	
  Event.wrap('John	
  Doe'))

Notify a simple String
key to be matched
@glaforge — @smaldini / #DV13-rtweb

!21
Reactor — UriSelector
• A UriTemplateSelector will match a String 

by extracting bits from a URI
!

– U(“/some/{path}”)
– Selectors.uri(“/some/{path}”)

@glaforge — @smaldini / #DV13-rtweb

!22
Reactor — UriSelector
Use a URI Selector and capture fragment
reactor.on(U('/some/**/{topic}')){	
  Event<String>	
  ev	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  def	
  s	
  =	
  ev.headers['topic']	
  
}	
  	
  	
  	
  	
  	
  	
  	
  
s will be ‘topic’
!

reactor.notify('/some/to/topic',	
  Event.wrap('John	
  Doe'))

Notify a simple String
URI key to be matched
@glaforge — @smaldini / #DV13-rtweb

!23
Reactor — Consumer, Function, Supplier, Predicate
public	
  interface	
  Consumer<T>	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  void	
  accept(T	
  t);	
  	
  
}	
  	
  	
  	
  	
  	
  	
  	
  

Generic Callback

!

public	
  interface	
  Supplier<T>	
  {	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  T	
  get();	
  	
  	
  
}	
  

Object Factory

!

public	
  interface	
  Function<T,	
  V>	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  V	
  apply(T	
  t);	
  
}	
  	
  	
  	
  	
  	
  	
  	
  

Map Operation

!

public	
  abstract	
  class	
  Predicate<T>	
  {	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  boolean	
  test(T	
  t);	
  	
  
}	
  	
  	
  
@glaforge — @smaldini / #DV13-rtweb

Filter Operation

!24
Reactor — Streams
●

−
−

Streams allow for composition of functions on data	

Callback++	

Netflix RxJava Observable, JDK 8 Stream
Stream<String>	
  str	
  =	
  obtainStream()	
  

Coerces to Function

!

str.map{	
  it.toUpperCase()	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  .filter{	
  someCondition()	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  .consume{	
  s	
  -­‐>	
  log.info	
  "consumed	
  string	
  $s"	
  }

Coerces to Predicate

@glaforge — @smaldini / #DV13-rtweb

Coerces to Consumer
!25
Reactor — Promises
●

−
−

Promises supersedes Java Future for composition	

Share common functions with Stream
Stateful: only 1 transition allowed
Promise<String>	
  p	
  =	
  doLater()	
  
!

String	
  s	
  =	
  p	
  
	
  .onSuccess	
  {	
  s	
  -­‐>	
  log.info	
  "consumed	
  string	
  $s"	
  }	
  
	
  	
  .onFailure	
  {	
  t	
  -­‐>	
  log.error	
  "$t.message"	
  }	
  
	
  	
  	
  .onComplete	
  {	
  log.info	
  'complete'	
  }	
  
	
  	
  	
  	
  .await(5,	
  SECONDS)	
  
!

p.map{	
  it.toUpperCase()	
  }.consume{s	
  -­‐>	
  log.info	
  "UC:	
  $s"}	
  

Block for a return value
@glaforge — @smaldini / #DV13-rtweb

!26
Reactor — Processor
●

−
−

Thin wrapper around Disruptor RingBuffer
Converts Disruptor API to Reactor API	

Uber fast performance for #UberFastData
Processor<Buffer>	
  proc	
  
!

Operation<Buffer>	
  op	
  =	
  proc.prepare()	
  
op.get().append(data).flip()	
  
op.commit()	
  
!

proc.batch(512)	
  {	
  it.append(data).flip()	
  }

Fill 512 slots and release once
@glaforge — @smaldini / #DV13-rtweb

!27
Reactor — Spring
!

Helpers to integrate Reactor into ApplicationContext	


●

!

−

@EnableReactor for easy configuration	

!

−

Wiring annotated handlers

@glaforge — @smaldini / #DV13-rtweb

!28
Reactor — Spring
Setup Environment

@Configuration	
  
@EnableReactor	
  
class	
  ReactorConfiguration	
  {	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  @Bean	
  Reactor	
  input(Environment	
  env)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  Reactors.reactor().env(env)	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .dispatcher(RING_BUFFER).get()	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  @Bean	
  Reactor	
  output(Environment	
  env)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  Reactors.reactor().env(env)	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  .dispatcher(RING_BUFFER).get()	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  
}
@glaforge — @smaldini / #DV13-rtweb

!29
Reactor — Spring
@Component	
  
class	
  SimpleHandler	
  {	
  

Inject reactor

!

	
  	
  @Autowired	
  Reactor	
  reactor	
  
!

	
  	
  @Selector('test.topic')	
  void	
  onTestTopic(String	
  s)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  Handle	
  data	
  
	
  	
  }	
  
}

Register consumer on @reactor

@glaforge — @smaldini / #DV13-rtweb

!30
Reactor — Spring
●

−
−
●
●

●

DispatcherTaskExecutor 	

Not really a high-scale TaskExecutor	

Used to get Spring components running in same thread as
Reactor Consumers	

ConversionService integration	

PromiseHandlerMethodReturnValueHandler (!)	

ReactorSubscribableChannel

@glaforge — @smaldini / #DV13-rtweb

!31
Reactor — Groovy
●

−
−
−
−

First class citizen language implementation	

@CompileStatic ready	

Prominent use of Closure as Consumers, Functions and
more	

Operator overloading for elegant programming	

Full Reactor system Builder

@glaforge — @smaldini / #DV13-rtweb

!32
Reactor — Groovy
Works with Groovy 2 CompileStatic

Coerce String to $(string)

@CompileStatic	
  
def	
  welcome()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  reactor.on('greetings')	
  {	
  String	
  s	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  reply	
  "hello	
  $s"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  reply	
  "how	
  are	
  you?"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  

Send data back using
replyTo key header

!

	
  	
  	
  	
  	
  	
  	
  	
  reactor.notify	
  'greetings',	
  'Jon'	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  reactor.send('greetings',	
  'Stephane')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  println	
  it	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  cancel()	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
}

Stop listening for replies

@glaforge — @smaldini / #DV13-rtweb

Coerce data arg to
Event.wrap(data)
Notify & Listen for replies
!33
Reactor — Groovy Promises and Streams
Build an async function

def	
  promise	
  =	
  Promises.task	
  {	
  longStuff();	
  1	
  }	
  get()	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
!

def	
  transformation	
  =	
  promise	
  |	
  {	
  it	
  +	
  1	
  }	
  
transformation.await()	
  ==	
  2	
  	
  	
  	
  	
  	
  

Pipe promise with the
!
def	
  deferredStream	
  =	
  Streams.defer().get()	
  	
  	
  	
  	
  	
  	
  
closure transformation
(deferredStream	
  &	
  {	
  it	
  >	
  2	
  })	
  <<	
  {	
  send(it)	
  }	
  
!

deferredStream	
  <<	
  1	
  <<	
  2	
  <<	
  3	
  <<	
  4

Filter the stream with
the right hand closure
predicate
@glaforge — @smaldini / #DV13-rtweb

Add callback after filter
Send data
!34
Reactor — Groovy Environment
Works with Groovy 2
@CompileStatic

Prepare an environment
builder

GroovyEnvironment.create	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  environment	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  defaultDispatcher	
  =	
  "test"	
  
!

which dispatcher to use
when creating a reactor

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  dispatcher('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  type	
  =	
  DispatcherType.SYNCHRONOUS	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  
Build a standard
}.environment()

Return a ready to
use Environment

@glaforge — @smaldini / #DV13-rtweb

Dispatcher

!35
Reactor — Groovy Environment
Build a named Reactor

GroovyEnvironment.create	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  reactor('test1')	
  {	
  
Intercept the data
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  stream('test')	
  {	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  consume	
  {	
  ev-­‐>	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
stream coming by the
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  log.info	
  ev.data	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
selector $(‘test’)
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  on('test')	
  {	
  
Stream builder
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  reply	
  it	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
}	
  

Attach inline consumers

@glaforge — @smaldini / #DV13-rtweb

!36
Reactor — Extensive Awesomeness
●

TCP Client/Server, with a Netty 4 implementation	


●

Buffer tools	


●

Sequencer support, for event ordering

●

Work Queue support with OoB Java Chronicle implementation	


●

Log Appender

@glaforge — @smaldini / #DV13-rtweb

!37
Reactor — Roadmap
1.1 discussions

●

−

StateBox: a safe tool for concurrent writes	


−

Better Timer management	


−

Spring XD, Spring 4	


−

Exploring Distributed Reactors	

●

Voice your interest and your use-case here

@glaforge — @smaldini / #DV13-rtweb

!38
Reactor — Roadmap
1.1 discussions

●

−

HTTP helpers

−

Improved RingBuffer API for multithreaded consumers
(slow consumers)

−

More Groovy Love: Buffer, TCP, Processor, Time,

@glaforge — @smaldini / #DV13-rtweb

!39
Reactor — Uber Community Contribs
●

−

Meltdown: A Clojure binding by @michaelklishin &
@ifesdjeen 	

https://github.com/clojurewerkz/meltdown

@glaforge — @smaldini / #DV13-rtweb

!40
Reactor — Uber Community Contribs
!

●

−

High Performance Couchbase ingestion by @daschl	

http://nitschinger.at/Using-the-Reactor-Processor-for-HighPerformance-TCP	

!

●

Benefits of using Reactor Processor, TCP and Batching
facilities

@glaforge — @smaldini / #DV13-rtweb

!41
Demo
2
t
r
a
P

Grails
Grails — The Age of Asynchronous
Fact #1:	

– HTTP request thread is critical path	

– Do the barely necessary for fast rendering	

– If it’s long*, do it in a separate thread

@glaforge — @smaldini / #DV13-rtweb

!44
Grails — The Age of Asynchronous
Fact #2:	

– Creating new Threads needs caution	

– Context switching hurts performances	

– Concurrent programming is tricky*

@glaforge — @smaldini / #DV13-rtweb

!45
Grails — The Age of Asynchronous

Fact #3:	

– Burden on your application is never constant	

– Scaling Up is a good start…	

– …And Scaling Out is only next

@glaforge — @smaldini / #DV13-rtweb

!46
Grails — The Age of Asynchronous

So I have to use background threads ?	

But using them might lead to issues and headaches ?	

And what if I really need to scale out ?

@glaforge — @smaldini / #DV13-rtweb

!47
Grails — Reactive Programming Recap
• Adding a level of indirection : 

Driving your application with Events
• Laziness is key
• Scale up/out by tweaking dispatching

@glaforge — @smaldini / #DV13-rtweb

!48
Grails — The Big Picture
Application
Service
Consumer
Service
Consumer

Publish/Subscribe
Events
Bus

Service
Consumer

@glaforge — @smaldini / #DV13-rtweb

Service
Consumer

Service
Consumer

!49
Grails — The Big Picture
Cloud
App
Publish/Subscribe

App
Events
Bus

App

App
App

@glaforge — @smaldini / #DV13-rtweb

!50
Introducing	
  GRAILS-­‐EVENTS	
  plugin
BOOM!

worse slide ever™
@glaforge — @smaldini / #DV13-rtweb

!51
Grails — Origins : Platform-Core plugin
• An initiative to provide modern tools for grails development	

!

• Among them: the Events API	

• An abstraction used in a few Grails applications today to
decouple logic from producers
!

• grails-events can be considered as 

Platform Core Events API 2.0
@glaforge — @smaldini / #DV13-rtweb

!52
Grails — Why a new plugin ?
• New features. And quite a few.	

– Streaming data, Selectors, Queue	

!

• Based on a new solid foundation – Reactor
– Where Platform-core Events best ideas have leaked	

!

• Semantic changes
– But relatively straightforward migration path

@glaforge — @smaldini / #DV13-rtweb

!53
Grails — Why a new plugin ?
• Lightweight, only focused on events	

!

• Ready to be embedded in a future Grails version	

• Complete the asynchronous story	

• Could enable runtime plugin deployment

@glaforge — @smaldini / #DV13-rtweb

!54
Grails — So what Grails Events is about
• Grails Apps and Plugins can use Events to:	

– Listen for plugins/app events	

– Start simple with in-memory eventing (#uberfastdata)	

– Do Asynchronous calls (default)	

– Increase in flexibility if required

@glaforge — @smaldini / #DV13-rtweb

!55
Grails — Installing Grails Events
• It’s a binary plugin (!)	

• Requires Grails 2.2+
repositories	
  {	
  
	
  	
  	
  	
  //...	
  	
  	
  	
  
	
  	
  	
  	
  mavenRepo	
  "http://repo.springsource.org/libs-­‐snapshot"	
  
	
  	
  	
  	
  mavenRepo	
  "http://repo.grails.org/grails/libs-­‐snapshots-­‐local/"	
  
}	
  
!

dependencies	
  {	
  
	
  	
  	
  	
  compile	
  'org.grails.plugins:events:1.0.0.BUILD-­‐SNAPSHOT'	
  
}	
  

@glaforge — @smaldini / #DV13-rtweb

!56
Grails — Semantics: Consumer
• A Consumer:	

– Accepts an Event	

– Is registered in a Service or Events artifact, or by calling on()	

– Can be thread safe 	

• Depending on the dispatcher type	

• Assuming the consumer is not registered more than once

@glaforge — @smaldini / #DV13-rtweb

!57
Grails — Semantics: Selector
• A Selector:	

– Matches an event key	

– Is paired with a consumer during its registration
– Any bean method can be transformed into consumer
with @Selector

@glaforge — @smaldini / #DV13-rtweb

!58
Grails — Semantics: Reactor
• A Reactor:	

– Is a dedicated Consumer Registry	

– Has an assigned Dispatcher	

– Uses a specific Event Router	

!

• Usually, if the Dispatcher doesn’t need to be adapted, reuse the
default reactor grailsReactor

@glaforge — @smaldini / #DV13-rtweb

!59
Grails — Pattern Examples : Event Driven CQRS
http://martinfowler.com/bliki/CQRS.html

Save a GORM entity
SaveService
GORM

DB

PostProcessingService

Insert Record

@glaforge — @smaldini / #DV13-rtweb

Trigger afterInsert
event

Consume afterInsert events

!60
Grails — Pattern Examples : Modular Architecture
Core application untouched

Trigger ‘request’ event

Main Application

RequestService

Notification Plugin

NotificationService

Create a decoupled module
@glaforge — @smaldini / #DV13-rtweb

Consume ‘request’ events
!61
Grails — Pattern Examples : Background Processing
Return immediately
Grails Controller

REST service

Request Service

HTTP Request

Trigger ‘request’
event (async)

Long REST call
@glaforge — @smaldini / #DV13-rtweb

!62
Grails — Sending Events (grails-platform-core)
def	
  user	
  =	
  new	
  User(params).save()	
  
!

event('mailRegistration',	
  user)	
  
	
  	
  
//event('mailRegistration',	
  user).waitFor()	
  
	
  	
  
//event	
  topic:'mailRegistration',	
  data:user	
  
	
  	
  
//event	
  topic:'mailRegistration',	
  data:user,	
  fork:false	
  
	
  	
  
render(view:'sendingRegistrationMail')

@glaforge — @smaldini / #DV13-rtweb

!63
Grails — Sending Events (grails-events)
def	
  user	
  =	
  new	
  User(params).save()	
  
!

event('mailRegistration',	
  user)	
  
	
  	
  	
  	
  	
  	
  	
  
event('mailRegistration',	
  user)	
  {	
  
	
  	
  	
  	
  if(it	
  ==	
  ‘end')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  cancel()	
  
	
  	
  	
  	
  }	
  
}	
  	
  	
  

Non blocking call to
trigger app consumers

Do things on each reply
Map notation

!

//	
  event	
  key:	
  'mailRegistration',	
  data:	
  user	
  
!

render(view:	
  'sendingRegistrationMail')
@glaforge — @smaldini / #DV13-rtweb

!64
Grails — Consuming Events (grails-platform-core)
class	
  UserService{	
  
	
  	
  	
  	
  @grails.events.Listener	
  
	
  	
  	
  	
  def	
  mailRegistration(User	
  user)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  sendMail	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to	
  user.mail	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  subject	
  "Confirmation"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html	
  g.render(template:"userMailConfirmation")	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  @grails.events.Listener(topic=	
  "mailRegistration")	
  
	
  	
  	
  	
  def	
  mailRegistration2(org.grails.plugin.platform.events.EventMessage	
  msg)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  sendMail{	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to	
  msg.data.mail	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  subject	
  "Confirmation"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html	
  g.render(template:	
  "userMailConfirmation")	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!65
Grails — Consuming Events (grails-events)
Consume on
Selector(method name)

class	
  UserService{	
  
	
  	
  
	
  	
  	
  	
  @reactor.spring.annotation.Selector	
  
	
  	
  	
  	
  def	
  mailRegistration(User	
  user){	
  
	
  	
  	
  	
  	
  	
  	
  	
  sendMail{	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to	
  user.mail	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  subject	
  "Confirmation"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html	
  g.render(template:	
  "userMailConfirmation")	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  

Consume on this
specific topic

!

	
  	
  	
  	
  @reactor.spring.annotation.Selector("mailRegistration")	
  
	
  	
  	
  	
  def	
  mailRegistration2(reactor.event.Event	
  msg){	
  
	
  	
  	
  	
  	
  	
  	
  	
  sendMail{	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to	
  msg.data.mail	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  subject	
  "Confirmation"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  html	
  g.render(template:"userMailConfirmation")	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

Event typed signature
to inspect enveloppe
(‘headers…)
!66
Grails — A new Artifact conf/XxxxEvents
includes	
  =	
  ['default']	
  

Merge with DefaultsEvents

!

doWithReactor	
  =	
  {	
  
	
  	
  	
  	
  reactor(EventsApi.GRAILS_REACTOR)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  on('someTopic')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  reply	
  'test'	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  reactor(‘someGormReactor')	
  {	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  dispatcher	
  =	
  new	
  SynchronousDispatcher()	
  
	
  	
  	
  	
  	
  	
  	
  	
  ext	
  'gorm',	
  true	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  

Build a GroovyEnvironment

Reactor Groovy Builders

!

Grails extension: accept GORM events

	
  	
  	
  	
  	
  	
  	
  	
  stream	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  consume	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  log.info	
  "Some	
  gorm	
  event	
  is	
  flowing	
  with	
  data	
  $it.data"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }.when(Throwable)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  log.error	
  "Ow	
  snap!",	
  it	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
}
@glaforge — @smaldini / #DV13-rtweb
!67
Grails — Reactor awesomeness : Selectors
• Listen for arbitrary keys	

• import static reactor.event.selector.Selectors.*
on(T(SpecificClassType))	
  {	
  
Listen for SpecificClassType
	
  	
  	
  	
  	
  	
  	
  	
  reply	
  it	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
}	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
!

Send using right key type

event(new	
  SpecificClassType(),	
  'data')	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
!
!

Listen for an URI

on(uri(‘/some/{captureIt}'))	
  {	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  reply	
  it.headers.captureIt	
  
}	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
!

Send using matching URI

event('/some/hourray',	
  'data')	
  	
  	
  	
  
@glaforge — @smaldini / #DV13-rtweb

!68
Grails — Reactor awesomeness : Stream API
• Reactive Extensions programming style	

• Avoid callback hell
Build a Stream to capture any reply
$(‘test’) consumers may reply
withStream	
  {	
  
	
  	
  	
  	
  event(key:	
  'test',	
  data:	
  1)	
  
}.when(Exception,	
  {	
  
If a consumer fails
	
  	
  	
  	
  log.info	
  "exception:$it"	
  
}).map	
  {	
  
Transform result
	
  	
  	
  	
  callExternalService(it)	
  
}.consume('clientKey',	
  reactor('browser'))
Reroute to key ‘clientKey’
on Reactor ‘browser’
@glaforge — @smaldini / #DV13-rtweb

!69
Grails — Reactor awesomeness: Promise API
• Grails 2.3 Promises become a Reactor Promises	

• Benefits from Dispatcher overriding
• Powerful once Combined with Consumers
dispatcher(ReactorPromise.PromiseDispatcher)	
  {	
  
	
  	
  	
  	
  type	
  =	
  DispatcherType.RingBuffer	
  
	
  	
  	
  	
  backlog	
  =	
  512	
  
}
task	
  {	
  
	
  	
  	
  	
  def	
  res	
  =	
  
longProcessing()	
  
	
  	
  	
  	
  render	
  res	
  
}
@glaforge — @smaldini / #DV13-rtweb

!70
Grails — Reactor awesomeness : Routing
• During event dispatching, consumers list is selected	

• Publish Subscribe is the default	

• Possible to assign different routing strategy
reactor('test1')	
  {	
  
	
  	
  	
  	
  routingStrategy	
  'round-­‐robin'	
  
	
  	
  	
  	
  on('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  reply	
  '1'	
  
Will reply 1, 2, 1, 2, 1, 2…
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  on('test')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  reply	
  '2'	
  
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  
}
@glaforge — @smaldini / #DV13-rtweb

!71
Grails — Extensibility
!

• Main extension points:	

– Dispatcher, Selector, Registry, EventRouter, Consumer
!

• Metadata in Reactor Events DSL:	

– ext(‘someExtension’, [ ‘doStuff’: true ])

@glaforge — @smaldini / #DV13-rtweb

!72
Grails — GORM events
• GORM is now an extension	

– Using ext(‘gorm’, true) on any candidate reactor	

– Applicable Selectors: simple topic form (beforeInsert...)	

– A boolean reply is evaluated as a cancel directive
reactor('someGormReactor'){	
  
	
  	
  	
  	
  dispatcher	
  =	
  new	
  SynchronousDispatcher()	
  
	
  	
  	
  	
  ext	
  'gorm',	
  true	
  
@Selector(reactor	
  =	
  'someGormReactor')	
  
}	
  	
  
@ReplyTo	
  
boolean	
  beforeValidate(Book	
  b){	
  
	
  	
  	
  	
  false	
  
}
@glaforge — @smaldini / #DV13-rtweb

!73
GRAILS-­‐EVENTS-­‐PUSH	
  plugin
Eventing over HTTP!

@glaforge — @smaldini / #DV13-rtweb

!74
Grails — Pattern Examples : “Realtime” web
Push reply to browser: Websocket, SSE, long-polling…

Reply a new event

ResponseService

Browser

Return immediately

@glaforge — @smaldini / #DV13-rtweb

Grails Controller

RequestService

Trigger async event

!75
Grails — An elegant solution to browser push
• Powered by Atmosphere 2	

• Automatically picks an adapted protocol:	

– WebSockets, ServerSideEvent, Streaming, Polling…	

• Consumer bridges for server-to-client push	

• Reactor bridge for client-to-server push	

• Javascript library

@glaforge — @smaldini / #DV13-rtweb

!76
Grails — Installing Grails Events Push
1. Install Grails Events plugin	

2. Install Grails Events Push plugin
grails.servlet.version	
  =	
  "3.0"	
  
grails.tomcat.nio	
  =	
  true	
  
!

Use a “long-connection” friendly
tomcat configuration

grails.project.dependency.resolution	
  =	
  {	
  
	
  	
  	
  	
  repositories	
  {	
  
	
  	
  	
  	
  //...	
  
	
  	
  	
  	
  	
  	
  	
  	
  mavenRepo	
  "https://oss.sonatype.org/content/repositories/snapshots"	
  
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  dependencies	
  {	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  //...	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  compile	
  'org.grails.plugins:events:1.0.0.BUILD-­‐SNAPSHOT'	
  
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  plugins	
  {	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  //...	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  runtime	
  ":jquery:1.10.2"	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  runtime	
  ":events-­‐push:1.0.0.BUILD-­‐SNAPSHOT"	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

!77
Grails — grails-events-push Lifecycle 1 - Handshake

Browser

EventsPushHandler

Adapt Protocol and Open
new persistent connection

@glaforge — @smaldini / #DV13-rtweb

!78
Grails — grails-events-push Lifecycle 2 - Register
Consumer registered on all Reactor with
‘browser’ extension enabled
Browser

Reactor(s)

Bridge a Client Consumer with a
remote Reactor Consumer

@glaforge — @smaldini / #DV13-rtweb

!79
Grails — grails-events-push Lifecycle 3 - Notify
RequestService consumes on matching
Selector within the ‘browser’ Reactor
Browser

‘browser’ Reactor

RequestService

Notify any key

@glaforge — @smaldini / #DV13-rtweb

!80
Grails — grails-events-push Lifecycle 4 - Consume
Notify ‘browser’ enabled
Reactor and match key
Browser

Reactor(s)

ResponseService

Push event (WS, SSE…)

@glaforge — @smaldini / #DV13-rtweb

!81
Grails — Generating Simple Browsers bridges
includes	
  =	
  'push'	
  
!

Conventional name to
override ‘browser’ reactor

doWithReactor	
  =	
  {	
  
	
  	
  	
  	
  reactor('browser')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  ext	
  'browser',	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'control',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'move',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'fire',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'leave'	
  
	
  	
  	
  	
  	
  	
  	
  	
  ]	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  reactor(‘grailsReactor')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  ext	
  'browser',	
  ['sleepBrowser']	
  

Bridge browser to these reactor
consumers $(‘control),…

!

	
  	
  	
  	
  	
  	
  	
  	
  stream(‘sleepBrowser')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  filter	
  {	
   	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  it.data	
  ==	
  'no'	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}

@glaforge — @smaldini / #DV13-rtweb

Bridge browser to this reactor
consumer $(‘sleepBrowser)

Prevent data ‘no’ to be
dispatched to browser bridges
!82
Grails — React on server side events
Inject grailsEvents.js (requires resources plugin)
Create a connection
between the browser and
the current Grails app
Listen for $(‘afterInsert’) events

@glaforge — @smaldini / #DV13-rtweb

!83
Grails — Generating Advanced Browsers bridges
includes	
  =	
  ['push']	
  
!

Include PushEvents (configure a
reactor for events from Browsers)

doWithReactor	
  =	
  {	
  
	
  	
  	
  	
  reactor(‘grailsReactor')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  ext	
  'gorm',	
  true	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  ext	
  'browser',	
  [	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'test':	
  true,	
  
	
   	
   	
   	
  	
  	
  	
  	
  	
  	
  'afterInsert':	
  [	
  
	
   	
   	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  browserFilter:	
  {m,	
  r	
  -­‐>	
  true	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ],	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  (R("sampleBro-­‐.*"))	
  :	
  true,	
  
	
  	
  	
  	
  	
  	
  	
  	
  ]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  reactor(EventsPushConstants.FROM_BROWSERS)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  ext	
  'browser',	
  [R("sampleBro-­‐.*")]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
}	
  

Listen on GORM events

Extension to bridge
Browsers consumers to
Server-side pair

Events are only routed, from
Browsers to bridged Browsers

@glaforge — @smaldini / #DV13-rtweb

Override “From Browsers” reactor
and bridge consumers

!84
Grails — The Bad Stuff
• events-si : Events API on top of Spring Integration	

– Not here (just) yet	

!

• events-vertx : Abandoned experiment	

– Working around Distributed Reactor	

!

• Stream DSL could be optimized	

– Reducing the number of objects

@glaforge — @smaldini / #DV13-rtweb

!85
Grails — Roadmap
• events: 	

– Document, especially for Migration from Platform Core	

– Stick with latest awesome features from Reactor	

• Still Many API to expose: Processors, Buffer, TCP, Queues,
Sequencer…	

!

• events-push -> events-atmosphere : 	

– Add support for replyTo	

– extract to standalone module : reactor-atmosphere
@glaforge — @smaldini / #DV13-rtweb

!86
Grails — Roadmap
• events-sockjs:	

– Involves Reactor work here 	

!

• events-si: 	

– Supports new events plugin	

!

• events-xx:	

– The plugin where you are the hero

@glaforge — @smaldini / #DV13-rtweb

!87
Demo
4
t
r
a
P

Summary
Groovy, Reactor, Grails and the realtime web
• Embrace modern reactive architectures with Groovy,
Reactor and Grails!	

• Groovy is a versatile language, that enables development of
concise and functional oriented applications	

• Reactor fuels your asynchronous and reactive applications
with its ultra fast dispatching engine and non-blocking model.	

• Grails supports your today's and tomorrow's web app design,
tooled with the right plugins you are prepared for responsive
and interactive applications
@glaforge — @smaldini / #DV13-rtweb

!90

Reactor grails realtime web devoxx 2013

  • 1.
    Groovy, Reactor, Grails
 & the realtime web Guillaume Laforge 
 @glaforge ! Stéphane Maldini
 @smaldini !
  • 2.
    Stéphane Maldini Consultant and Reactorcommitter at . ! @smaldini
  • 3.
  • 4.
    Reactor — Housekeeping ! •Tweet questions during the presentation – @ProjectReactor ! • Stop us anywhere if you have a question – There are no stupid questions, only stupid answers! @glaforge — @smaldini / #DV13-rtweb !4
  • 5.
    Reactor — ReactiveArchitecture ? REACTIVE AGILE EVENT DRIVEN SCALABLE AVAILABLE @glaforge — @smaldini / #DV13-rtweb !5
  • 6.
    Reactor — ReactiveArchitecture ? • A good description is available on: 
 http://www.reactivemanifesto.org/ ! • Functional Programming helps as it is stimulus based by nature ! • Groovy is a perfect candidate: 
 Closures and DSL are first class citizen ! • Reactor completes the picture by providing abstractions @glaforge — @smaldini / #DV13-rtweb !6
  • 7.
    Reactor — Threadingmodel matters • Context switching hurts performances • Locking hurts performances • Message passing hurts performances • Blocking for a thread hurts performances • Creating Threads needs memory @glaforge — @smaldini / #DV13-rtweb !7
  • 8.
    Reactor — Dealingwith performances • Actors solve the locking and context switching issues 
 by becoming state boxes • One thread assigned per consumer • One thread will ever access a property
 • Non Blocking Programming solves thread creation and waiting issues by delaying logic • Callback will be executed when possible (Lazy) • Reallocate the blocking time to process something else @glaforge — @smaldini / #DV13-rtweb !8
  • 9.
    Reactor — LMAXDisruptor and Ring Buffer • LMAX Disruptor deals with message passing issues • Based on a Ring Buffer structure • “Mechanical Sympathy” in Disruptor ! • http://lmax-exchange.github.com/disruptor/files/ Disruptor-1.0.pdf • http://mechanitis.blogspot.co.uk/2011/06/dissecting-disruptorwhats-so-special.html @glaforge — @smaldini / #DV13-rtweb !9
  • 10.
    Reactor — Disruptorperformances @glaforge — @smaldini / #DV13-rtweb !10
  • 11.
    Reactor — Trisha’spretty picture of Disruptor http://mechanitis.blogspot.co.uk/2011/07/dissectingdisruptor-writing-to-ring.html @glaforge — @smaldini / #DV13-rtweb !11
  • 12.
    Reactor — Inlove with Disruptor • Reactor best performances are derived from LMAX Disruptor ! • LMAX Disruptor can be considered 
 as an evolution of the Actor Model: ! • Still avoid locking and deals with context switching • Producer/Consumer decoupled • Add Pipelining, Batching and more @glaforge — @smaldini / #DV13-rtweb !12
  • 13.
    Reactor — Afoundation part of Spring IO @glaforge — @smaldini / #DV13-rtweb !13
  • 14.
    Reactor — Whatis it? ! • Reactor is a distillation of other libraries and best-practices – Elements of other patterns and libraries 
 surface throughout Reactor's abstractions ! • http://stackoverflow.com/questions/16595393/akka-or-reactor @glaforge — @smaldini / #DV13-rtweb !14
  • 15.
    Reactor — Whatcan I build with it? • Reactor applications are reactive – Reactive Extensions in .NET – Netflix RxJava – Observer pattern ! • Reactor applications route events based on a Selector – Like a routing topic, but can be any object – Regex, URI template, Class.isAssingableFrom, custom logic @glaforge — @smaldini / #DV13-rtweb !15
  • 16.
    Reactor — Landscape @glaforge— @smaldini / #DV13-rtweb !16
  • 17.
    Reactor — Whatdoes it look like? Create a reactor context def  env  =  new  Environment()   ! Build a reactor parameter def  reactor  =   Reactors.reactor().env(env).dispatcher(RING_BUFFER).get()   ! reactor.on($('topic')){  Event<String>  ev  -­‐>                  println  "Hello  $ev.data"   }   React on ‘topic’ events ! reactor.notify('topic',  Event.wrap('John  Doe')) Trigger reactor ‘topic’ key @glaforge — @smaldini / #DV13-rtweb !17
  • 18.
    Reactor — Selectors •Selectors are the left-hand side of an equality comparison ! – A Selector can be created from any object using $(obj) 
 (or the long form: Selectors.object(obj)) ! – A Selector can extract data from the matched key ! – Predicate<T> Selectors can be created to match on domainspecific criteria like header values @glaforge — @smaldini / #DV13-rtweb !18
  • 19.
    Reactor — RegexSelector •A RegexSelector will match a String by executing the regex over it – R(“some.(.*)”) – Selectors.regex(“some.(.*)”) @glaforge — @smaldini / #DV13-rtweb !19
  • 20.
    Reactor — RegexSelector ! •A RegexSelector will match a String 
 by executing the regex over it ! – R(“some.(.*)”) ! – Selectors.regex(“some.(.*)”) @glaforge — @smaldini / #DV13-rtweb !20
  • 21.
    Reactor — RegexSelector Usea Regex Selector and capture group reactor.on(R('some.(.+)')){  Event<String>  ev  -­‐>                  def  s  =  ev.headers.get('group1')   }                                 s will be ‘topic’ ! reactor.notify('some.topic',  Event.wrap('John  Doe')) Notify a simple String key to be matched @glaforge — @smaldini / #DV13-rtweb !21
  • 22.
    Reactor — UriSelector •A UriTemplateSelector will match a String 
 by extracting bits from a URI ! – U(“/some/{path}”) – Selectors.uri(“/some/{path}”) @glaforge — @smaldini / #DV13-rtweb !22
  • 23.
    Reactor — UriSelector Usea URI Selector and capture fragment reactor.on(U('/some/**/{topic}')){  Event<String>  ev  -­‐>                  def  s  =  ev.headers['topic']   }                 s will be ‘topic’ ! reactor.notify('/some/to/topic',  Event.wrap('John  Doe')) Notify a simple String URI key to be matched @glaforge — @smaldini / #DV13-rtweb !23
  • 24.
    Reactor — Consumer,Function, Supplier, Predicate public  interface  Consumer<T>  {                  void  accept(T  t);     }                 Generic Callback ! public  interface  Supplier<T>  {                    T  get();       }   Object Factory ! public  interface  Function<T,  V>  {                  V  apply(T  t);   }                 Map Operation ! public  abstract  class  Predicate<T>  {                    boolean  test(T  t);     }       @glaforge — @smaldini / #DV13-rtweb Filter Operation !24
  • 25.
    Reactor — Streams ● − − Streamsallow for composition of functions on data Callback++ Netflix RxJava Observable, JDK 8 Stream Stream<String>  str  =  obtainStream()   Coerces to Function ! str.map{  it.toUpperCase()  }                  .filter{  someCondition()  }                  .consume{  s  -­‐>  log.info  "consumed  string  $s"  } Coerces to Predicate @glaforge — @smaldini / #DV13-rtweb Coerces to Consumer !25
  • 26.
    Reactor — Promises ● − − Promisessupersedes Java Future for composition Share common functions with Stream Stateful: only 1 transition allowed Promise<String>  p  =  doLater()   ! String  s  =  p    .onSuccess  {  s  -­‐>  log.info  "consumed  string  $s"  }      .onFailure  {  t  -­‐>  log.error  "$t.message"  }        .onComplete  {  log.info  'complete'  }          .await(5,  SECONDS)   ! p.map{  it.toUpperCase()  }.consume{s  -­‐>  log.info  "UC:  $s"}   Block for a return value @glaforge — @smaldini / #DV13-rtweb !26
  • 27.
    Reactor — Processor ● − − Thinwrapper around Disruptor RingBuffer Converts Disruptor API to Reactor API Uber fast performance for #UberFastData Processor<Buffer>  proc   ! Operation<Buffer>  op  =  proc.prepare()   op.get().append(data).flip()   op.commit()   ! proc.batch(512)  {  it.append(data).flip()  } Fill 512 slots and release once @glaforge — @smaldini / #DV13-rtweb !27
  • 28.
    Reactor — Spring ! Helpersto integrate Reactor into ApplicationContext ● ! − @EnableReactor for easy configuration ! − Wiring annotated handlers @glaforge — @smaldini / #DV13-rtweb !28
  • 29.
    Reactor — Spring SetupEnvironment @Configuration   @EnableReactor   class  ReactorConfiguration  {   !                @Bean  Reactor  input(Environment  env)  {                                  Reactors.reactor().env(env)                                                  .dispatcher(RING_BUFFER).get()                  }                 !                @Bean  Reactor  output(Environment  env)  {                                  Reactors.reactor().env(env)                                                  .dispatcher(RING_BUFFER).get()                  }                 } @glaforge — @smaldini / #DV13-rtweb !29
  • 30.
    Reactor — Spring @Component   class  SimpleHandler  {   Inject reactor !    @Autowired  Reactor  reactor   !    @Selector('test.topic')  void  onTestTopic(String  s)  {                      //  Handle  data      }   } Register consumer on @reactor @glaforge — @smaldini / #DV13-rtweb !30
  • 31.
    Reactor — Spring ● − − ● ● ● DispatcherTaskExecutor Not really a high-scale TaskExecutor Used to get Spring components running in same thread as Reactor Consumers ConversionService integration PromiseHandlerMethodReturnValueHandler (!) ReactorSubscribableChannel @glaforge — @smaldini / #DV13-rtweb !31
  • 32.
    Reactor — Groovy ● − − − − Firstclass citizen language implementation @CompileStatic ready Prominent use of Closure as Consumers, Functions and more Operator overloading for elegant programming Full Reactor system Builder @glaforge — @smaldini / #DV13-rtweb !32
  • 33.
    Reactor — Groovy Workswith Groovy 2 CompileStatic Coerce String to $(string) @CompileStatic   def  welcome()  {                  reactor.on('greetings')  {  String  s  -­‐>                                  reply  "hello  $s"                                  reply  "how  are  you?"                  }   Send data back using replyTo key header !                reactor.notify  'greetings',  'Jon'   !                reactor.send('greetings',  'Stephane')  {                                  println  it                                  cancel()                  }   } Stop listening for replies @glaforge — @smaldini / #DV13-rtweb Coerce data arg to Event.wrap(data) Notify & Listen for replies !33
  • 34.
    Reactor — GroovyPromises and Streams Build an async function def  promise  =  Promises.task  {  longStuff();  1  }  get()                       ! def  transformation  =  promise  |  {  it  +  1  }   transformation.await()  ==  2             Pipe promise with the ! def  deferredStream  =  Streams.defer().get()               closure transformation (deferredStream  &  {  it  >  2  })  <<  {  send(it)  }   ! deferredStream  <<  1  <<  2  <<  3  <<  4 Filter the stream with the right hand closure predicate @glaforge — @smaldini / #DV13-rtweb Add callback after filter Send data !34
  • 35.
    Reactor — GroovyEnvironment Works with Groovy 2 @CompileStatic Prepare an environment builder GroovyEnvironment.create  {                  environment  {                                  defaultDispatcher  =  "test"   ! which dispatcher to use when creating a reactor                                dispatcher('test')  {                                                  type  =  DispatcherType.SYNCHRONOUS                                  }                  }                 Build a standard }.environment() Return a ready to use Environment @glaforge — @smaldini / #DV13-rtweb Dispatcher !35
  • 36.
    Reactor — GroovyEnvironment Build a named Reactor GroovyEnvironment.create  {                  reactor('test1')  {   Intercept the data                                stream('test')  {                                                                                  consume  {  ev-­‐>                                                           stream coming by the                                                                log.info  ev.data                                       selector $(‘test’)                                                }                                                                              }                                                                                                                                    on('test')  {   Stream builder                                                reply  it                                  }                  }                                                                                                             }   Attach inline consumers @glaforge — @smaldini / #DV13-rtweb !36
  • 37.
    Reactor — ExtensiveAwesomeness ● TCP Client/Server, with a Netty 4 implementation ● Buffer tools ● Sequencer support, for event ordering ● Work Queue support with OoB Java Chronicle implementation ● Log Appender @glaforge — @smaldini / #DV13-rtweb !37
  • 38.
    Reactor — Roadmap 1.1discussions ● − StateBox: a safe tool for concurrent writes − Better Timer management − Spring XD, Spring 4 − Exploring Distributed Reactors ● Voice your interest and your use-case here @glaforge — @smaldini / #DV13-rtweb !38
  • 39.
    Reactor — Roadmap 1.1discussions ● − HTTP helpers − Improved RingBuffer API for multithreaded consumers (slow consumers) − More Groovy Love: Buffer, TCP, Processor, Time, @glaforge — @smaldini / #DV13-rtweb !39
  • 40.
    Reactor — UberCommunity Contribs ● − Meltdown: A Clojure binding by @michaelklishin & @ifesdjeen https://github.com/clojurewerkz/meltdown @glaforge — @smaldini / #DV13-rtweb !40
  • 41.
    Reactor — UberCommunity Contribs ! ● − High Performance Couchbase ingestion by @daschl http://nitschinger.at/Using-the-Reactor-Processor-for-HighPerformance-TCP ! ● Benefits of using Reactor Processor, TCP and Batching facilities @glaforge — @smaldini / #DV13-rtweb !41
  • 42.
  • 43.
  • 44.
    Grails — TheAge of Asynchronous Fact #1: – HTTP request thread is critical path – Do the barely necessary for fast rendering – If it’s long*, do it in a separate thread @glaforge — @smaldini / #DV13-rtweb !44
  • 45.
    Grails — TheAge of Asynchronous Fact #2: – Creating new Threads needs caution – Context switching hurts performances – Concurrent programming is tricky* @glaforge — @smaldini / #DV13-rtweb !45
  • 46.
    Grails — TheAge of Asynchronous Fact #3: – Burden on your application is never constant – Scaling Up is a good start… – …And Scaling Out is only next @glaforge — @smaldini / #DV13-rtweb !46
  • 47.
    Grails — TheAge of Asynchronous So I have to use background threads ? But using them might lead to issues and headaches ? And what if I really need to scale out ? @glaforge — @smaldini / #DV13-rtweb !47
  • 48.
    Grails — ReactiveProgramming Recap • Adding a level of indirection : 
 Driving your application with Events • Laziness is key • Scale up/out by tweaking dispatching @glaforge — @smaldini / #DV13-rtweb !48
  • 49.
    Grails — TheBig Picture Application Service Consumer Service Consumer Publish/Subscribe Events Bus Service Consumer @glaforge — @smaldini / #DV13-rtweb Service Consumer Service Consumer !49
  • 50.
    Grails — TheBig Picture Cloud App Publish/Subscribe App Events Bus App App App @glaforge — @smaldini / #DV13-rtweb !50
  • 51.
    Introducing  GRAILS-­‐EVENTS  plugin BOOM! worseslide ever™ @glaforge — @smaldini / #DV13-rtweb !51
  • 52.
    Grails — Origins: Platform-Core plugin • An initiative to provide modern tools for grails development ! • Among them: the Events API • An abstraction used in a few Grails applications today to decouple logic from producers ! • grails-events can be considered as 
 Platform Core Events API 2.0 @glaforge — @smaldini / #DV13-rtweb !52
  • 53.
    Grails — Whya new plugin ? • New features. And quite a few. – Streaming data, Selectors, Queue ! • Based on a new solid foundation – Reactor – Where Platform-core Events best ideas have leaked ! • Semantic changes – But relatively straightforward migration path @glaforge — @smaldini / #DV13-rtweb !53
  • 54.
    Grails — Whya new plugin ? • Lightweight, only focused on events ! • Ready to be embedded in a future Grails version • Complete the asynchronous story • Could enable runtime plugin deployment @glaforge — @smaldini / #DV13-rtweb !54
  • 55.
    Grails — Sowhat Grails Events is about • Grails Apps and Plugins can use Events to: – Listen for plugins/app events – Start simple with in-memory eventing (#uberfastdata) – Do Asynchronous calls (default) – Increase in flexibility if required @glaforge — @smaldini / #DV13-rtweb !55
  • 56.
    Grails — InstallingGrails Events • It’s a binary plugin (!) • Requires Grails 2.2+ repositories  {          //...                mavenRepo  "http://repo.springsource.org/libs-­‐snapshot"          mavenRepo  "http://repo.grails.org/grails/libs-­‐snapshots-­‐local/"   }   ! dependencies  {          compile  'org.grails.plugins:events:1.0.0.BUILD-­‐SNAPSHOT'   }   @glaforge — @smaldini / #DV13-rtweb !56
  • 57.
    Grails — Semantics:Consumer • A Consumer: – Accepts an Event – Is registered in a Service or Events artifact, or by calling on() – Can be thread safe • Depending on the dispatcher type • Assuming the consumer is not registered more than once @glaforge — @smaldini / #DV13-rtweb !57
  • 58.
    Grails — Semantics:Selector • A Selector: – Matches an event key – Is paired with a consumer during its registration – Any bean method can be transformed into consumer with @Selector @glaforge — @smaldini / #DV13-rtweb !58
  • 59.
    Grails — Semantics:Reactor • A Reactor: – Is a dedicated Consumer Registry – Has an assigned Dispatcher – Uses a specific Event Router ! • Usually, if the Dispatcher doesn’t need to be adapted, reuse the default reactor grailsReactor @glaforge — @smaldini / #DV13-rtweb !59
  • 60.
    Grails — PatternExamples : Event Driven CQRS http://martinfowler.com/bliki/CQRS.html Save a GORM entity SaveService GORM DB PostProcessingService Insert Record @glaforge — @smaldini / #DV13-rtweb Trigger afterInsert event Consume afterInsert events !60
  • 61.
    Grails — PatternExamples : Modular Architecture Core application untouched Trigger ‘request’ event Main Application RequestService Notification Plugin NotificationService Create a decoupled module @glaforge — @smaldini / #DV13-rtweb Consume ‘request’ events !61
  • 62.
    Grails — PatternExamples : Background Processing Return immediately Grails Controller REST service Request Service HTTP Request Trigger ‘request’ event (async) Long REST call @glaforge — @smaldini / #DV13-rtweb !62
  • 63.
    Grails — SendingEvents (grails-platform-core) def  user  =  new  User(params).save()   ! event('mailRegistration',  user)       //event('mailRegistration',  user).waitFor()       //event  topic:'mailRegistration',  data:user       //event  topic:'mailRegistration',  data:user,  fork:false       render(view:'sendingRegistrationMail') @glaforge — @smaldini / #DV13-rtweb !63
  • 64.
    Grails — SendingEvents (grails-events) def  user  =  new  User(params).save()   ! event('mailRegistration',  user)                 event('mailRegistration',  user)  {          if(it  ==  ‘end')  {                  cancel()          }   }       Non blocking call to trigger app consumers Do things on each reply Map notation ! //  event  key:  'mailRegistration',  data:  user   ! render(view:  'sendingRegistrationMail') @glaforge — @smaldini / #DV13-rtweb !64
  • 65.
    Grails — ConsumingEvents (grails-platform-core) class  UserService{          @grails.events.Listener          def  mailRegistration(User  user)  {                  sendMail  {                          to  user.mail                          subject  "Confirmation"                          html  g.render(template:"userMailConfirmation")                  }          }   !        @grails.events.Listener(topic=  "mailRegistration")          def  mailRegistration2(org.grails.plugin.platform.events.EventMessage  msg)  {                  sendMail{                        to  msg.data.mail                        subject  "Confirmation"                        html  g.render(template:  "userMailConfirmation")                  }          }   } @glaforge — @smaldini / #DV13-rtweb !65
  • 66.
    Grails — ConsumingEvents (grails-events) Consume on Selector(method name) class  UserService{              @reactor.spring.annotation.Selector          def  mailRegistration(User  user){                  sendMail{                          to  user.mail                          subject  "Confirmation"                          html  g.render(template:  "userMailConfirmation")                  }          }   Consume on this specific topic !        @reactor.spring.annotation.Selector("mailRegistration")          def  mailRegistration2(reactor.event.Event  msg){                  sendMail{                          to  msg.data.mail                          subject  "Confirmation"                          html  g.render(template:"userMailConfirmation")                  }          }   } @glaforge — @smaldini / #DV13-rtweb Event typed signature to inspect enveloppe (‘headers…) !66
  • 67.
    Grails — Anew Artifact conf/XxxxEvents includes  =  ['default']   Merge with DefaultsEvents ! doWithReactor  =  {          reactor(EventsApi.GRAILS_REACTOR)  {                  on('someTopic')  {                          reply  'test'                                          }                                                                                                        }                                                                                                                                        reactor(‘someGormReactor')  {                                                                                                            dispatcher  =  new  SynchronousDispatcher()                  ext  'gorm',  true                                                                                                                   Build a GroovyEnvironment Reactor Groovy Builders ! Grails extension: accept GORM events                stream  {                          consume  {                                  log.info  "Some  gorm  event  is  flowing  with  data  $it.data"                          }.when(Throwable)  {                                  log.error  "Ow  snap!",  it                          }                                                                                                                                                        }                                                      }                                                                                                                                                         } @glaforge — @smaldini / #DV13-rtweb !67
  • 68.
    Grails — Reactorawesomeness : Selectors • Listen for arbitrary keys • import static reactor.event.selector.Selectors.* on(T(SpecificClassType))  {   Listen for SpecificClassType                reply  it                                   }                                                                                                 ! Send using right key type event(new  SpecificClassType(),  'data')                                                           ! ! Listen for an URI on(uri(‘/some/{captureIt}'))  {                                                                                          reply  it.headers.captureIt   }                                                                                                                                     ! Send using matching URI event('/some/hourray',  'data')         @glaforge — @smaldini / #DV13-rtweb !68
  • 69.
    Grails — Reactorawesomeness : Stream API • Reactive Extensions programming style • Avoid callback hell Build a Stream to capture any reply $(‘test’) consumers may reply withStream  {          event(key:  'test',  data:  1)   }.when(Exception,  {   If a consumer fails        log.info  "exception:$it"   }).map  {   Transform result        callExternalService(it)   }.consume('clientKey',  reactor('browser')) Reroute to key ‘clientKey’ on Reactor ‘browser’ @glaforge — @smaldini / #DV13-rtweb !69
  • 70.
    Grails — Reactorawesomeness: Promise API • Grails 2.3 Promises become a Reactor Promises • Benefits from Dispatcher overriding • Powerful once Combined with Consumers dispatcher(ReactorPromise.PromiseDispatcher)  {          type  =  DispatcherType.RingBuffer          backlog  =  512   } task  {          def  res  =   longProcessing()          render  res   } @glaforge — @smaldini / #DV13-rtweb !70
  • 71.
    Grails — Reactorawesomeness : Routing • During event dispatching, consumers list is selected • Publish Subscribe is the default • Possible to assign different routing strategy reactor('test1')  {          routingStrategy  'round-­‐robin'          on('test')  {                  reply  '1'   Will reply 1, 2, 1, 2, 1, 2…        }                        on('test')  {                  reply  '2'          }                 } @glaforge — @smaldini / #DV13-rtweb !71
  • 72.
    Grails — Extensibility ! •Main extension points: – Dispatcher, Selector, Registry, EventRouter, Consumer ! • Metadata in Reactor Events DSL: – ext(‘someExtension’, [ ‘doStuff’: true ]) @glaforge — @smaldini / #DV13-rtweb !72
  • 73.
    Grails — GORMevents • GORM is now an extension – Using ext(‘gorm’, true) on any candidate reactor – Applicable Selectors: simple topic form (beforeInsert...) – A boolean reply is evaluated as a cancel directive reactor('someGormReactor'){          dispatcher  =  new  SynchronousDispatcher()          ext  'gorm',  true   @Selector(reactor  =  'someGormReactor')   }     @ReplyTo   boolean  beforeValidate(Book  b){          false   } @glaforge — @smaldini / #DV13-rtweb !73
  • 74.
    GRAILS-­‐EVENTS-­‐PUSH  plugin Eventing overHTTP! @glaforge — @smaldini / #DV13-rtweb !74
  • 75.
    Grails — PatternExamples : “Realtime” web Push reply to browser: Websocket, SSE, long-polling… Reply a new event ResponseService Browser Return immediately @glaforge — @smaldini / #DV13-rtweb Grails Controller RequestService Trigger async event !75
  • 76.
    Grails — Anelegant solution to browser push • Powered by Atmosphere 2 • Automatically picks an adapted protocol: – WebSockets, ServerSideEvent, Streaming, Polling… • Consumer bridges for server-to-client push • Reactor bridge for client-to-server push • Javascript library @glaforge — @smaldini / #DV13-rtweb !76
  • 77.
    Grails — InstallingGrails Events Push 1. Install Grails Events plugin 2. Install Grails Events Push plugin grails.servlet.version  =  "3.0"   grails.tomcat.nio  =  true   ! Use a “long-connection” friendly tomcat configuration grails.project.dependency.resolution  =  {          repositories  {          //...                  mavenRepo  "https://oss.sonatype.org/content/repositories/snapshots"          }                                            dependencies  {                                  //...                                                    compile  'org.grails.plugins:events:1.0.0.BUILD-­‐SNAPSHOT'          }                                                                                            plugins  {                                                                                            //...                                                                                                    runtime  ":jquery:1.10.2"                                                                                                                                  runtime  ":events-­‐push:1.0.0.BUILD-­‐SNAPSHOT"                                                }   } @glaforge — @smaldini / #DV13-rtweb !77
  • 78.
    Grails — grails-events-pushLifecycle 1 - Handshake Browser EventsPushHandler Adapt Protocol and Open new persistent connection @glaforge — @smaldini / #DV13-rtweb !78
  • 79.
    Grails — grails-events-pushLifecycle 2 - Register Consumer registered on all Reactor with ‘browser’ extension enabled Browser Reactor(s) Bridge a Client Consumer with a remote Reactor Consumer @glaforge — @smaldini / #DV13-rtweb !79
  • 80.
    Grails — grails-events-pushLifecycle 3 - Notify RequestService consumes on matching Selector within the ‘browser’ Reactor Browser ‘browser’ Reactor RequestService Notify any key @glaforge — @smaldini / #DV13-rtweb !80
  • 81.
    Grails — grails-events-pushLifecycle 4 - Consume Notify ‘browser’ enabled Reactor and match key Browser Reactor(s) ResponseService Push event (WS, SSE…) @glaforge — @smaldini / #DV13-rtweb !81
  • 82.
    Grails — GeneratingSimple Browsers bridges includes  =  'push'   ! Conventional name to override ‘browser’ reactor doWithReactor  =  {          reactor('browser')  {                  ext  'browser',  [                          'control',                          'move',                          'fire',                          'leave'                  ]          }          reactor(‘grailsReactor')  {                  ext  'browser',  ['sleepBrowser']   Bridge browser to these reactor consumers $(‘control),… !                stream(‘sleepBrowser')  {                          filter  {                                    it.data  ==  'no'                          }                  }          }   } @glaforge — @smaldini / #DV13-rtweb Bridge browser to this reactor consumer $(‘sleepBrowser) Prevent data ‘no’ to be dispatched to browser bridges !82
  • 83.
    Grails — Reacton server side events Inject grailsEvents.js (requires resources plugin) Create a connection between the browser and the current Grails app Listen for $(‘afterInsert’) events @glaforge — @smaldini / #DV13-rtweb !83
  • 84.
    Grails — GeneratingAdvanced Browsers bridges includes  =  ['push']   ! Include PushEvents (configure a reactor for events from Browsers) doWithReactor  =  {          reactor(‘grailsReactor')  {                  ext  'gorm',  true                            ext  'browser',  [                                                                                                                                        'test':  true,                      'afterInsert':  [                                        browserFilter:  {m,  r  -­‐>  true  }                                                                                            ],                                                                                                                                                            (R("sampleBro-­‐.*"))  :  true,                  ]                                                                                                                                                      }                                                                                                                                                              reactor(EventsPushConstants.FROM_BROWSERS)  {                  ext  'browser',  [R("sampleBro-­‐.*")]                                                                                    }                                                                                                             }   Listen on GORM events Extension to bridge Browsers consumers to Server-side pair Events are only routed, from Browsers to bridged Browsers @glaforge — @smaldini / #DV13-rtweb Override “From Browsers” reactor and bridge consumers !84
  • 85.
    Grails — TheBad Stuff • events-si : Events API on top of Spring Integration – Not here (just) yet ! • events-vertx : Abandoned experiment – Working around Distributed Reactor ! • Stream DSL could be optimized – Reducing the number of objects @glaforge — @smaldini / #DV13-rtweb !85
  • 86.
    Grails — Roadmap •events: – Document, especially for Migration from Platform Core – Stick with latest awesome features from Reactor • Still Many API to expose: Processors, Buffer, TCP, Queues, Sequencer… ! • events-push -> events-atmosphere : – Add support for replyTo – extract to standalone module : reactor-atmosphere @glaforge — @smaldini / #DV13-rtweb !86
  • 87.
    Grails — Roadmap •events-sockjs: – Involves Reactor work here ! • events-si: – Supports new events plugin ! • events-xx: – The plugin where you are the hero @glaforge — @smaldini / #DV13-rtweb !87
  • 88.
  • 89.
  • 90.
    Groovy, Reactor, Grailsand the realtime web • Embrace modern reactive architectures with Groovy, Reactor and Grails! • Groovy is a versatile language, that enables development of concise and functional oriented applications • Reactor fuels your asynchronous and reactive applications with its ultra fast dispatching engine and non-blocking model. • Grails supports your today's and tomorrow's web app design, tooled with the right plugins you are prepared for responsive and interactive applications @glaforge — @smaldini / #DV13-rtweb !90