Reactor grails realtime web devoxx 2013

3,562 views

Published on

Published in: Technology

Reactor grails realtime web devoxx 2013

  1. 1. Groovy, Reactor, Grails 
 & the realtime web Guillaume Laforge 
 @glaforge ! Stéphane Maldini
 @smaldini !
  2. 2. Stéphane Maldini Consultant and Reactor committer at . ! @smaldini
  3. 3. 1 t r a P Reactor
  4. 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. 5. Reactor — Reactive Architecture ? REACTIVE AGILE EVENT DRIVEN SCALABLE AVAILABLE @glaforge — @smaldini / #DV13-rtweb !5
  6. 6. 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
  7. 7. 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
  8. 8. 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
  9. 9. 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
  10. 10. Reactor — Disruptor performances @glaforge — @smaldini / #DV13-rtweb !10
  11. 11. Reactor — Trisha’s pretty picture of Disruptor http://mechanitis.blogspot.co.uk/2011/07/dissectingdisruptor-writing-to-ring.html @glaforge — @smaldini / #DV13-rtweb !11
  12. 12. 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
  13. 13. Reactor — A foundation part of Spring IO @glaforge — @smaldini / #DV13-rtweb !13
  14. 14. 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
  15. 15. 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
  16. 16. Reactor — Landscape @glaforge — @smaldini / #DV13-rtweb !16
  17. 17. 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
  18. 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. 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. 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. 21. 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
  22. 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. 23. 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
  24. 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. 25. 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
  26. 26. 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
  27. 27. 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
  28. 28. Reactor — Spring ! Helpers to integrate Reactor into ApplicationContext ● ! − @EnableReactor for easy configuration ! − Wiring annotated handlers @glaforge — @smaldini / #DV13-rtweb !28
  29. 29. 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
  30. 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. 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. 32. 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
  33. 33. 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
  34. 34. 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
  35. 35. 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
  36. 36. 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
  37. 37. 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
  38. 38. 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
  39. 39. 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
  40. 40. Reactor — Uber Community Contribs ● − Meltdown: A Clojure binding by @michaelklishin & @ifesdjeen https://github.com/clojurewerkz/meltdown @glaforge — @smaldini / #DV13-rtweb !40
  41. 41. 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
  42. 42. Demo
  43. 43. 2 t r a P Grails
  44. 44. 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
  45. 45. 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
  46. 46. 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
  47. 47. 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
  48. 48. 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
  49. 49. Grails — The Big Picture Application Service Consumer Service Consumer Publish/Subscribe Events Bus Service Consumer @glaforge — @smaldini / #DV13-rtweb Service Consumer Service Consumer !49
  50. 50. Grails — The Big Picture Cloud App Publish/Subscribe App Events Bus App App App @glaforge — @smaldini / #DV13-rtweb !50
  51. 51. Introducing  GRAILS-­‐EVENTS  plugin BOOM! worse slide ever™ @glaforge — @smaldini / #DV13-rtweb !51
  52. 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. 53. 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
  54. 54. 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
  55. 55. 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
  56. 56. 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
  57. 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. 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. 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. 60. 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
  61. 61. 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
  62. 62. 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
  63. 63. 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
  64. 64. 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
  65. 65. 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
  66. 66. 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
  67. 67. 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
  68. 68. 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
  69. 69. 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
  70. 70. 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
  71. 71. 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
  72. 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. 73. 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
  74. 74. GRAILS-­‐EVENTS-­‐PUSH  plugin Eventing over HTTP! @glaforge — @smaldini / #DV13-rtweb !74
  75. 75. 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
  76. 76. 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
  77. 77. 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
  78. 78. Grails — grails-events-push Lifecycle 1 - Handshake Browser EventsPushHandler Adapt Protocol and Open new persistent connection @glaforge — @smaldini / #DV13-rtweb !78
  79. 79. 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
  80. 80. 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
  81. 81. 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
  82. 82. 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
  83. 83. 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
  84. 84. 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
  85. 85. 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
  86. 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. 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. 88. Demo
  89. 89. 4 t r a P Summary
  90. 90. 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

×