90
Guillaume Laforge @glaforge ! Groovy, Reactor, Grails & the realtime web Stéphane Maldini @smaldini !

Reactor grails realtime web devoxx 2013

Embed Size (px)

Citation preview

Page 1: Reactor grails realtime web   devoxx 2013

Guillaume Laforge @glaforge !

Groovy, Reactor, Grails & the realtime web

Stéphane Maldini@smaldini !

Page 2: Reactor grails realtime web   devoxx 2013

Stéphane Maldini

Consultant and Reactor committer at .

!

@smaldini

Page 3: Reactor grails realtime web   devoxx 2013

Reactor

Part 1

Page 4: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Housekeeping

!

• Tweet questions during the presentation – @ProjectReactor

!

• Stop us anywhere if you have a question – There are no stupid questions, only stupid answers!

!4

Page 5: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Reactive Architecture ?

!5

EVENT DRIVENAGILE

REACTIVE

SCALABLE

AVAILABLE

Page 6: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Reactive Architecture ?

!6

• 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

Page 7: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Threading model matters

!7

• Context switching hurts performances

• Locking hurts performances

• Message passing hurts performances

• Blocking for a thread hurts performances

• Creating Threads needs memory

Page 8: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Dealing with performances

!8

• 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

Page 9: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — LMAX Disruptor and Ring Buffer

!9

• 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-disruptor-whats-so-special.html

Page 10: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Disruptor performances

!10

Page 11: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Trisha’s pretty picture of Disruptor

!11

http://mechanitis.blogspot.co.uk/2011/07/dissecting-disruptor-writing-to-ring.html

Page 12: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — In love with Disruptor

!12

• 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

Page 13: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — A foundation part of Spring IO

!13

Page 14: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!14

Page 15: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!15

Page 16: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Landscape

!16

Page 17: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — What does it look like?

!17

def  env  =  new  Environment()  !def  reactor  =  Reactors.reactor().env(env).dispatcher(RING_BUFFER).get()  !reactor.on($('topic')){  Event<String>  ev  -­‐>                  println  "Hello  $ev.data"  }  !reactor.notify('topic',  Event.wrap('John  Doe'))

Create a reactor context

Trigger reactor ‘topic’ key

React on ‘topic’ events

Build a reactor parameter

Page 18: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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 domain-specific criteria like header values

!18

Page 19: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — RegexSelector

• A RegexSelector will match a String by executing the regex over it – R(“some.(.*)”) – Selectors.regex(“some.(.*)”)

!19

Page 20: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb

Reactor — RegexSelector

!

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

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

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

!20

Page 21: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — RegexSelector

!21

reactor.on(R('some.(.+)')){  Event<String>  ev  -­‐>                  def  s  =  ev.headers.get('group1')  }                                !

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

Use a Regex Selector and capture group

Notify a simple String key to be matched

s will be ‘topic’

Page 22: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — UriSelector

• A UriTemplateSelector will match a String by extracting bits from a URI !

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

!22

Page 23: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — UriSelector

!23

reactor.on(U('/some/**/{topic}')){  Event<String>  ev  -­‐>                  def  s  =  ev.headers['topic']  }                !

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

Use a URI Selector and capture fragment

Notify a simple String URI key to be matched

s will be ‘topic’

Page 24: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Consumer, Function, Supplier, Predicate

!24

public  interface  Consumer<T>  {                  void  accept(T  t);    }                !

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

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

public  abstract  class  Predicate<T>  {                    boolean  test(T  t);    }      

Generic Callback

Object Factory

Map Operation

Filter Operation

Page 25: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Streams

● Streams allow for composition of functions on data − Callback++ − Netflix RxJava Observable, JDK 8 Stream

!25

Stream<String>  str  =  obtainStream()  !

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

Coerces to Predicate

Coerces to Function

Coerces to Consumer

Page 26: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Promises

● Promises supersedes Java Future for composition − Share common functions with Stream − Stateful: only 1 transition allowed

!26

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

Page 27: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Processor● Thin wrapper around Disruptor RingBuffer − Converts Disruptor API to Reactor API − Uber fast performance for #UberFastData

!27

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

Page 28: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb

Reactor — Spring

!

● Helpers to integrate Reactor into ApplicationContext !

− @EnableReactor for easy configuration !

− Wiring annotated handlers

!28

Page 29: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Spring

!29

@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()                  }                }

Setup Environment

Page 30: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Spring

!30

@Component  class  SimpleHandler  {  !

   @Autowired  Reactor  reactor  !

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

Inject reactor

Register consumer on @reactor

Page 31: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!31

Page 32: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!32

Page 33: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Groovy

!33

@CompileStatic  def  welcome()  {                  reactor.on('greetings')  {  String  s  -­‐>                                  reply  "hello  $s"                                  reply  "how  are  you?"                  }  !                reactor.notify  'greetings',  'Jon'  !                reactor.send('greetings',  'Stephane')  {                                  println  it                                  cancel()                  }  }

Works with Groovy 2 CompileStaticCoerce String to $(string)

Send data back using replyTo key header

Coerce data arg to Event.wrap(data)

Notify & Listen for repliesStop listening for replies

Page 34: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Groovy Promises and Streams

!34

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

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

def  deferredStream  =  Streams.defer().get()              (deferredStream  &  {  it  >  2  })  <<  {  send(it)  }  !

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

Build an async function

Pipe promise with the closure transformation

Filter the stream with the right hand closure

predicate

Add callback after filter

Send data

Page 35: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Groovy Environment

!35

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

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

Works with Groovy 2 @CompileStatic

Prepare an environment builder

which dispatcher to use when creating a reactor

Build a standard DispatcherReturn a ready to

use Environment

Page 36: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Groovy Environment

!36

GroovyEnvironment.create  {                  reactor('test1')  {                                  stream('test')  {                                                                                  consume  {  ev-­‐>                                                                                                                                                        log.info  ev.data                                                                                                                                  }                                                                              }                                                                                                                                              on('test')  {                                                  reply  it                                  }                  }                                                                                                            }  

Build a named Reactor

Intercept the data stream coming by the

selector $(‘test’)

Stream builder

Attach inline consumers

Page 37: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!37

Page 38: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!38

Page 39: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Roadmap

● 1.1 discussions − HTTP helpers

− Improved RingBuffer API for multithreaded consumers

(slow consumers)

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

!39

Page 40: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Uber Community Contribs

● Meltdown: A Clojure binding by @michaelklishin & @ifesdjeen

− https://github.com/clojurewerkz/meltdown

!40

Page 41: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Reactor — Uber Community Contribs

!

● High Performance Couchbase ingestion by @daschl − http://nitschinger.at/Using-the-Reactor-Processor-for-High-

Performance-TCP !

● Benefits of using Reactor Processor, TCP and Batching facilities

!41

Page 42: Reactor grails realtime web   devoxx 2013

Demo

Page 43: Reactor grails realtime web   devoxx 2013

Grails

Part 2

Page 44: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!44

Page 45: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — The Age of Asynchronous

Fact #2: – Creating new Threads needs caution – Context switching hurts performances – Concurrent programming is tricky*

!45

Page 46: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!46

Page 47: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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 ?

!47

Page 48: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Reactive Programming Recap

• Adding a level of indirection : Driving your application with Events

• Laziness is key • Scale up/out by tweaking dispatching

!48

Page 49: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — The Big Picture

!49

Events Bus

Publish/Subscribe

Service Consumer

Service Consumer

Service Consumer

Service Consumer

Service Consumer

Application

Page 50: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — The Big Picture

!50

Events Bus

Publish/Subscribe

App

App

App

App

App

Cloud

Page 51: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb !51

Introducing  GRAILS-­‐EVENTS  plugin

BOOM!

worse slide ever™

Page 52: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!52

Page 53: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!53

Page 54: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!54

Page 55: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!55

Page 56: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Installing Grails Events

• It’s a binary plugin (!) • Requires Grails 2.2+

!56

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'  }  

Page 57: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!57

Page 58: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!58

Page 59: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!59

Page 60: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Pattern Examples : Event Driven CQRS

!60

GORM

http://martinfowler.com/bliki/CQRS.html

DBPostProcessingService

SaveService

Consume afterInsert events

Save a GORM entity

Insert RecordTrigger afterInsert

event

Page 61: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Pattern Examples : Modular Architecture

!61

Notification Plugin

RequestServiceMain Application

NotificationService

Trigger ‘request’ event

Create a decoupled module Consume ‘request’ events

Core application untouched

Page 62: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Pattern Examples : Background Processing

!62

REST service

Grails Controller HTTP Request

Return immediately

Request Service

Trigger ‘request’ event (async)

Long REST call

Page 63: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Sending Events (grails-platform-core)

!63

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')

Page 64: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Sending Events (grails-events)

!64

def  user  =  new  User(params).save()  !

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

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

render(view:  'sendingRegistrationMail')

Non blocking call to trigger app consumers

Do things on each reply

Map notation

Page 65: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Consuming Events (grails-platform-core)

!65

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")                  }          }  }

Page 66: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

Grails — Consuming Events (grails-events)

!66

Consume on Selector(method name)

Consume on this specific topic

Event typed signature to inspect enveloppe

(‘headers…)

Page 67: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

includes  =  ['default']  !doWithReactor  =  {          reactor(EventsApi.GRAILS_REACTOR)  {                  on('someTopic')  {                          reply  'test'                                          }                                                                                                        }                                                                                                                                        reactor(‘someGormReactor')  {                                                                                                            dispatcher  =  new  SynchronousDispatcher()                  ext  'gorm',  true                                                                                                                  !                stream  {                          consume  {                                  log.info  "Some  gorm  event  is  flowing  with  data  $it.data"                          }.when(Throwable)  {                                  log.error  "Ow  snap!",  it                          }                                                                                                                                                                                                                          }                                                      }                                                                                                                                                                                                }

Grails — A new Artifact conf/XxxxEvents

!67

Merge with DefaultsEvents

Build a GroovyEnvironment

Reactor Groovy Builders

Grails extension: accept GORM events

Page 68: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Reactor awesomeness : Selectors

• Listen for arbitrary keys • import static reactor.event.selector.Selectors.*

!68

on(T(SpecificClassType))  {                  reply  it                                  }                                                                                                !

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

!

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

event('/some/hourray',  'data')        

Listen for an URI

Listen for SpecificClassType

Send using right key type

Send using matching URI

Page 69: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Reactor awesomeness : Stream API

• Reactive Extensions programming style • Avoid callback hell

!69

withStream  {          event(key:  'test',  data:  1)  }.when(Exception,  {          log.info  "exception:$it"  }).map  {          callExternalService(it)  }.consume('clientKey',  reactor('browser'))

If a consumer fails

Build a Stream to capture any reply

$(‘test’) consumers may reply

Transform result

Reroute to key ‘clientKey’ on Reactor ‘browser’

Page 70: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Reactor awesomeness: Promise API

• Grails 2.3 Promises become a Reactor Promises • Benefits from Dispatcher overriding • Powerful once Combined with Consumers

!70

dispatcher(ReactorPromise.PromiseDispatcher)  {          type  =  DispatcherType.RingBuffer          backlog  =  512  }

task  {          def  res  =  longProcessing()          render  res  }

Page 71: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Reactor awesomeness : Routing

• During event dispatching, consumers list is selected • Publish Subscribe is the default • Possible to assign different routing strategy

!71

reactor('test1')  {          routingStrategy  'round-­‐robin'          on('test')  {                  reply  '1'          }                        on('test')  {                  reply  '2'          }                }

Will reply 1, 2, 1, 2, 1, 2…

Page 72: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Extensibility

!

• Main extension points: – Dispatcher, Selector, Registry, EventRouter, Consumer

!

• Metadata in Reactor Events DSL: – ext(‘someExtension’, [ ‘doStuff ’: true ])

!72

Page 73: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!73

reactor('someGormReactor'){          dispatcher  =  new  SynchronousDispatcher()          ext  'gorm',  true  }     @Selector(reactor  =  'someGormReactor')  

@ReplyTo  boolean  beforeValidate(Book  b){          false  }

Page 74: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb !74

GRAILS-­‐EVENTS-­‐PUSH  pluginEventing over HTTP!

Page 75: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Pattern Examples : “Realtime” web

!75

Browser

ResponseService

Grails Controller

Return immediately

RequestService

Trigger async event

Reply a new eventPush reply to browser: Websocket, SSE, long-polling…

Page 76: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!76

Page 77: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Installing Grails Events Push

1. Install Grails Events plugin 2. Install Grails Events Push plugin

!77

grails.servlet.version  =  "3.0"  grails.tomcat.nio  =  true  !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"                                                }  }

Use a “long-connection” friendly tomcat configuration

Page 78: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — grails-events-push Lifecycle 1 - Handshake

!78

Browser EventsPushHandler

Adapt Protocol and Open new persistent connection

Page 79: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — grails-events-push Lifecycle 2 - Register

!79

Browser Reactor(s)

Bridge a Client Consumer with a remote Reactor Consumer

Consumer registered on all Reactor with ‘browser’ extension enabled

Page 80: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — grails-events-push Lifecycle 3 - Notify

!80

Browser ‘browser’ Reactor

Notify any key

RequestService

RequestService consumes on matching Selector within the ‘browser’ Reactor

Page 81: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — grails-events-push Lifecycle 4 - Consume

!81

Browser Reactor(s)

Push event (WS, SSE…)

ResponseService

Notify ‘browser’ enabled Reactor and match key

Page 82: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Generating Simple Browsers bridges

!82

includes  =  'push'  !doWithReactor  =  {          reactor('browser')  {                  ext  'browser',  [                          'control',                          'move',                          'fire',                          'leave'                  ]          }          reactor(‘grailsReactor')  {                  ext  'browser',  ['sleepBrowser']  !                stream(‘sleepBrowser')  {                          filter  {                                    it.data  ==  'no'                          }                  }          }  }

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

Conventional name to override ‘browser’ reactor

Bridge browser to this reactor consumer $(‘sleepBrowser)

Prevent data ‘no’ to be dispatched to browser bridges

Page 83: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — React on server side events

!83

Inject grailsEvents.js (requires resources plugin)

Create a connection between the browser and

the current Grails app

Listen for $(‘afterInsert’) events

Page 84: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Generating Advanced Browsers bridges

!84

includes  =  ['push']  !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-­‐.*")]                                                                                                                                                }                                                                                                            }  

Include PushEvents (configure a reactor for events from Browsers)

Listen on GORM events

Extension to bridge Browsers consumers to

Server-side pair

Override “From Browsers” reactor and bridge consumersEvents are only routed, from

Browsers to bridged Browsers

Page 85: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!85

Page 86: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

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

!86

Page 87: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb

Grails — Roadmap

• events-sockjs: – Involves Reactor work here

!

• events-si: – Supports new events plugin

!

• events-xx: – The plugin where you are the hero

!87

Page 88: Reactor grails realtime web   devoxx 2013

Demo

Page 89: Reactor grails realtime web   devoxx 2013

Summary

Part 4

Page 90: Reactor grails realtime web   devoxx 2013

@glaforge — @smaldini / #DV13-rtweb

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

!90