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

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


    THANK YOU

    Q&A


    Vert.x and RxJava (eclipsecon)

    By petermd

    Vert.x and RxJava (eclipsecon)

    Talk on VertX and RxJava from eclipsecon2014

    • 20,182