Vert.x and RxJava
@petermd
eclipsecon 2014
BIO
- CTO at Donnerwood Media
- Social / Mobile Software Developer
- High-Performance Servers
- Telcos, Gaming, Startups
- Vert.x
- mod-rxvertx
- github.com/petermd
REACTIVE
programming
Fork()
for (;;) { fd = accept(listenfd, ...);
if ( (pid = fork()) == 0 ) { close(listenfd);
/* Process request */
exit(0); } close(fd); }
CONCURRENCY
C10
poll()
do { rc=poll(fds, nfds, timeout); current_size = nfds; for (i = 0; i < current_size; i++) { if(fds[i].revents == 0) continue; rc = recv(fds[i].fd, buffer, sizeof(buffer), 0); if (rc < 0) {
/* Not ready yet */ } .
/* Do something */ . } while(TRUE);
CONCURRENCY
C100
ASYNC PROGRAMMING IS
HARD
PROTO
COLS
ASYNC PROGRAMMING IS
UGLY
Error Propogation
fs.readdir(source, function(err, files) {
if(err){
console.log('Error finding files: '+err)
}else{
files.forEach(function(filename,fileIndex){
console.log(filename)
gm(source+filename).size(function(err,values){
if(err){
console.log('Error identifying file size: '+err)
}else{
console.log(filename+' : '+values)
aspect=(values.width/values.height)
widths.forEach(function(width,widthIndex){
height=Math.round(width/aspect)
console.log('resizing '+filename+'to '+height+'x'+height)
this
.resize(width,height)
.write(destination+'w'+width+'_'+filename,function(err) {
if(err)
console.log('Error writing file: '+err)
})
}.bind(this))
}
})
})
}
})
CHECK EVERYTHING
'cos if you think handling errors is hard
(not handling errors is worse)
GOTO ERR;
handling non errors isn't great either
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
WHAT ABOUT THREADS?
- light-weight
- linear
- exceptions
- multi-core
CONCURRENCY
C1k
FUTURE IS REACTIVE
-
them > us
- responsive
- resilient
- ..need a better model
ReacTIVE EXTENSIONS
- Part of .NET
- Netflix adapted for Server
- Other ports
- RxJS, RxCpp,Rx.rb,Rx.py
WHAT IS RX?
"a library for composing asynchronous and event-based programs by using observable sequences"
OBSERVABLE
- Iterable but Async
- Observer
- Operators
- Subscribers
- Reliable Error Propagation
- Zero or More elements
OBSERVER
interface Observer<T> {
void onNext(T value);
void onCompleted();
void onError(Throwable t);
}
OPERATORS
-
map
-
flatMap
-
concat
-
zip / join / reduce
-
buffer / window
- rescue
- ...
EXAMPLES
Simple Sequence
myStringService
.fetch()
.subscribe { v -> println("Got: "+v) }
EXAMPLES
Transform
myStringService
.fetch()
.map { v -> v.toLowerCase() }
.subscribe(...)
EXAMPLES
TRANSFORM ONLINE
myStringService
.fetch()
.flatMap { v -> myTranslationService.translate(v) }
.subscribe(...)
EXAMPLES
MERGE
Observable<String> s=myStringService.fetch().publish()
Observable<String> lc=s.map { v -> v.toLowerCase() }
Observable<String> tr=s.flatMap { v -> myTranslateService.translate(v) }
Observable
.zip(lc,tr,{ word, translated -> { return word+"="+translated } })
.subscribe(
{ v -> println(v) },
{ e -> println("ERROR:"+e) }
)
MOD-RXVertX
-
Observable
- void async(...,Handler<T>)
- Obserable<T> observe(...)
- Read/Write Streams
- Useful Functions
VERTX EXAMPLE
EVENT BUS
RxEventBus eb=new RxEventBus(vertx.eventBus());
eb.<String>registerHandler("ping")
.subscribe( (RxMessage<String>) (m) -> {
m.reply("pong")
})
eb
.send("ping","yolo")
.subscribe((RxMessage<String>)(m) -> {
out.println("got:"+m.body());
});
PATTERNS
- PROCESS
- STREAM
- FILTER
- RENDER
- COMMAND
-
RETRY
- FLOW CONTROL
PROCESS
HTTP SERVER
RxHttpServer server=new RxHttpServer(...);
server
.http()
.subscribe((RxHttpServerRequest)(req) -> {
// Handle request and request.toObservable() inside
// a new Observable
});
PROCESS
HTTPCLIENT
RxHttpClient client=new RxHttpClient(...);
client
.getNow("/someurl)
.flatMap(parseResponse)
.map(handleResponse)
// Subscription used to map output to response
.subscribe(...)
STREAM
CONVERSATION
eb.send("guest","you'll have tea")
.flatMap((RxMessage)(resp) -> {
return resp.reply("ah you will");
})
.flatMap((RxMessage)(resp) -> {
return resp.reply("pour-tea");
})
.subscribe(...)
STREAM
PIPELINE
rx.<String>observeStream("pint",1)
.map((Func1<RxStream,Integer>)(s) -> {
// request next block
s.next(...);
// forward current block
return s.value();
})
.subscribe(...)
FILTER
Observable<HttpServerRequest> req;
req=Observable
.just(req)
.filter(checkValid) // remove request if handled eg redirect
.map(checkAuth) // map it if just adding data
.flatMap(lookupAuth) // flatMap if you need a remote call
.map(..process request..)
.subscribe(
renderResponse,
renderError
)
RENDER
BASIC TYPES
/** Render string */ public static void render(HttpServerResponse resp, String value) { resp .headers().add("Content-Type","text/plain;charset=UTF8"); resp .setChunked(true) .end(value); }
void render(HttpServerResponse resp, JsonObject value) {..}
void renderErr(HttpServerResponse resp, int code, String msg) {..}
RENDER
OBSERVABLE
void render(HttpServerResponse resp, Observable ob) {
// map value + error to renderer
// completed without value -> response already sent
}
HttpSupport.render(resp,process);
COMMAND
HTTP UPLOAD
Observable<Buffer> in=request.toObservable();
HttpCommand<> cmd=new HttpCommand(request,in.map(..));
Observable<HttpCommand> cmd=HttpSupport.waitFor(cmd);
COMMAND
JSON Request
/** Return Observable<HttpCommand<JsonObject>> */
public static Observable jsonRequest(RxHttpServerRequest request) {
HttpCommand req=
new HttpCommand(
request,
request
.asObservable()
.reduce(mergeBuffers)
.map(toJson));
return waitFor(req);
}
COMMAND
USAGE
Obserable .just(request) .flatMap(HttpSupport.jsonRequest) .map((HttpCommand)(cmd) -> {
// cmd.body is the JsonObject })
RETRY
eventBus
.observeSend("db",request)
.retry(2)
.subscribe(...)
FLOW CONTROL
FAST PRODUCER
Observable<String> firehose=rx.<String>observeStream("twitter","*")
.map((RxStream)(s) -> { s.next(..); return s.value(); })
.map((String)(s) -> { ..render.. })
RxSupport.stream(firehose,output);
FLOW CONTROL
USING REGULATOR
Regulator reg=new Regulator();
Observable<String> firehose=rx.<String>observeStream("twitter","*")
.lift(reg)
.map((RxStream)(s) -> { s.next(..); return s.value(); })
.map((String)(s) -> { ..render.. })
reg.stream(firehose,output);
SUMMARY
- Async Programming is complex
- RxJava gives you
- Readable programs
- Reliable error handling
- Re-usable patterns
- http://github.com/vert-x/mod-rxvertx
- RxJava 0.17.1
THANK YOU
Q&A
Copy of Vert.x and RxJava (eclipsecon)
By Denis Stoyanov
Copy of Vert.x and RxJava (eclipsecon)
Talk on VertX and RxJava from eclipsecon2014
- 2,020