Reactor grails realtime web devoxx 2013
-
Upload
stephane-maldini -
Category
Technology
-
view
2.311 -
download
0
Transcript of Reactor grails realtime web devoxx 2013
![Page 1: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/1.jpg)
Guillaume Laforge @glaforge !
Groovy, Reactor, Grails & the realtime web
Stéphane Maldini@smaldini !
![Page 2: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/2.jpg)
Stéphane Maldini
Consultant and Reactor committer at .
!
@smaldini
![Page 3: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/3.jpg)
Reactor
Part 1
![Page 4: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/4.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/5.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/6.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/7.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/8.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/9.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/10.jpg)
@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb
Reactor — Disruptor performances
!10
![Page 11: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/11.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/12.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/13.jpg)
@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb
Reactor — A foundation part of Spring IO
!13
![Page 14: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/14.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/15.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/16.jpg)
@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb
Reactor — Landscape
!16
![Page 17: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/17.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/18.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/19.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/20.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/21.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/22.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/23.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/24.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/25.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/26.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/27.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/28.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/29.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/30.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/31.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/32.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/33.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/34.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/35.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/36.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/37.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/38.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/39.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/40.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/41.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/42.jpg)
Demo
![Page 43: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/43.jpg)
Grails
Part 2
![Page 44: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/44.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/45.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/46.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/47.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/48.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/49.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/50.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/51.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/52.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/53.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/54.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/55.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/56.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/57.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/58.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/59.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/60.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/61.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/62.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/63.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/64.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/65.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/66.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/67.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/68.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/69.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/70.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/71.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/72.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/73.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/74.jpg)
@glaforge — @smaldini / #DV13-rtweb@glaforge — @smaldini / #DV13-rtweb !74
GRAILS-‐EVENTS-‐PUSH pluginEventing over HTTP!
![Page 75: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/75.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/76.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/77.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/78.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/79.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/80.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/81.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/82.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/83.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/84.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/85.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/86.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/87.jpg)
@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](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/88.jpg)
Demo
![Page 89: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/89.jpg)
Summary
Part 4
![Page 90: Reactor grails realtime web devoxx 2013](https://reader034.fdocuments.in/reader034/viewer/2022042518/554ec766b4c9053c4b8b4db3/html5/thumbnails/90.jpg)
@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