Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reactive Ruby - building web apps with JRuby and Ratpack

Reactive Ruby - building web apps with JRuby and Ratpack

Slides for my talk about reactive Ruby and building high performant web apps with JRuby and Ratpack.io at the RUG::B meetup 2017/03.

Max Mulatz

March 02, 2017
Tweet

More Decks by Max Mulatz

Other Decks in Programming

Transcript

  1. Reactive Ruby

    View Slide

  2. Reactive Ruby
    - web apps with JRuby and Ratpack -

    View Slide

  3. max

    View Slide

  4. max
    ! klappradla
    " klappradla

    View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. limits

    View Slide

  9. $
    GIL

    View Slide

  10. blocking IO

    View Slide

  11. client server db

    View Slide

  12. client server db


    View Slide

  13. View Slide

  14. non-blocking IO

    View Slide

  15. client server db

    View Slide

  16. client server db

    View Slide

  17. View Slide

  18. View Slide

  19. View Slide

  20. “…gain the performance and
    concurrency benefits of Java without
    writing any Java code or XML”
    -joe kutner-

    View Slide

  21. # ratpack.io

    View Slide

  22. “It is built on Java 8, Netty and
    reactive principles"
    # netty.io
    -ratpack.io-

    View Slide

  23. “It provides just enough for writing
    practical, high performance, apps.”
    -ratpack.io-

    View Slide

  24. #reactive )

    View Slide

  25. “So let's cut the bullshit.

    Reactive programming is programming with
    asynchronous data streams”
    - @andrestaltz-
    # The introduction to Reactive Programming you've been missing

    View Slide

  26. iterator ♻
    +
    observer +

    View Slide

  27. “non-blocking communication allows recipients
    to only consume resources while active, leading
    to less system overhead”
    - reactivemanifesto-
    # reactivemanifesto.org

    View Slide

  28. # reactivex.io/
    Rx* libs ,

    View Slide

  29. # Get evens and square each
    some_source
    .select { |x| x.even? }
    .map { |x| x * x }
    .subscribe { |x| puts x.to_s }
    # github.com/ReactiveX/RxRuby

    View Slide

  30. ratpack -

    View Slide

  31. public class Main {
    public static void main(String... args) throws Exception {
    RatpackServer.start(server -> server
    .handlers(chain -> chain
    .get(ctx -> ctx.render("Hello World"))
    )
    );
    }
    }
    # ratpack.io/manual/current/launching.html#launching

    View Slide

  32. # Gemfile
    gem 'jbundler'
    # Jarfile
    jar 'io.ratpack:ratpack-core', '1.4.0'
    jar 'org.slf4j:slf4j-simple', '1.7.20'

    View Slide

  33. $ bundle install

    View Slide

  34. $ bundle exec jbundle install

    View Slide

  35. # github.com/klappradla/jruby_ratpack_examples/hello_world
    require 'java'
    require 'jruby/core_ext'
    require 'bundler/setup'
    Bundler.require
    java_import 'ratpack.server.RatpackServer'
    RatpackServer.start do |server|
    server.handlers do |chain|
    chain.get do |ctx|
    ctx.render('Hello World from Ratpack / JRuby')
    end
    end
    end

    View Slide

  36. View Slide

  37. blocking IO ?

    View Slide

  38. “A promise is a representation of a value which
    will become available later. Methods such as
    map(Function) […] allow a pipeline of
    “operations” to be specified, that the value will
    travel through as it becomes available.”
    -ratpack docs-
    # ratpack.io/manual/current/api/ratpack/exec/Promise.html

    View Slide

  39. # ratpack.io/manual/current/async.html#performing_blocking_operations_eg_io
    java_import 'ratpack.server.RatpackServer'
    java_import 'ratpack.exec.Blocking'
    require 'json'
    RatpackServer.start do |server|
    server.handlers do |chain|
    chain.get('music') do |ctx|
    Blocking
    .get { DB[:albums].all }
    .then { |data| ctx.render(JSON.dump(data))}
    end
    end
    end

    View Slide

  40. RatpackServer.start do |server|
    server.handlers do |chain|
    chain.get('music') do |ctx|
    Blocking
    .get { DB[:albums].all }
    .then { |data| ctx.render(JSON.dump(data))}
    end
    end
    end

    View Slide

  41. RatpackServer.start do |server|
    server.handlers do |chain|
    chain.get('music') do |ctx|
    Blocking
    .get { DB[:albums].all }
    .map { |data| JSON.dump(data) }
    .then { |data| ctx.render(data)}
    end
    end
    end

    View Slide

  42. non-blocking HTTP ?

    View Slide

  43. class Server
    def self.run
    RatpackServer.start do |server|
    server.handlers do |chain|
    chain.all(RequestLogger.ncsa)
    chain.get('music', Handler::Music)
    chain.get('planets', Handler::Planets)
    chain.all(Handler::NotFound)
    end
    end
    end
    end
    # github.com/klappradla/jruby_ratpack_examples/http_example

    View Slide

  44. # github.com/klappradla/jruby_ratpack_examples/http_example
    module Handler
    class Base
    def self.handle(ctx)
    new(ctx).handle
    end
    def initialize(ctx)
    @ctx = ctx
    end
    attr_reader :ctx
    def handle
    raise NotImplementedError
    end
    end
    end

    View Slide

  45. # github.com/klappradla/jruby_ratpack_examples/http_example
    java_import 'ratpack.http.client.HttpClient'
    require_relative 'base'
    module Handler
    class Planets < Base
    URL = java.net.URI.new('http://swapi.co/api/planets')
    def handle
    ctx
    .get(HttpClient.java_class)
    .get(URL)
    .map { |resp| resp.get_body }
    .map { |body| body.get_text }
    .then { |data| render(data) }
    end
    private
    def render(data)
    resp = ctx.get_response
    header = 'application/json;charset=UTF-8'
    resp.send(header, data)
    end
    end
    end

    View Slide

  46. View Slide

  47. # github.com/klappradla/jruby_ratpack_examples/sinatra

    View Slide

  48. # github.com/klappradla/jruby_ratpack_examples/benchmarks
    # Sinatra
    Running 30s test @ http://localhost:5050
    4 threads and 100 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 284.63ms 358.37ms 1.95s 85.07%
    Req/Sec 145.18 72.13 434.00 65.54%
    16392 requests in 30.08s, 64.94MB read
    Socket errors: connect 0, read 0, write 0, timeout 72
    Non-2xx or 3xx responses: 1
    Requests/sec: 545.00
    Transfer/sec: 2.16MB
    # Ratpack
    Running 30s test @ http://localhost:5050
    4 threads and 100 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 150.36ms 228.64ms 1.86s 88.18%
    Req/Sec 338.10 129.48 710.00 71.18%
    32746 requests in 30.08s, 127.09MB read
    Requests/sec: 1088.56
    Transfer/sec: 4.22MB

    View Slide

  49. # github.com/klappradla/jruby_ratpack_examples/benchmarks
    # Sinatra
    Running 30s test @ http://localhost:5050
    4 threads and 100 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 284.63ms 358.37ms 1.95s 85.07%
    Req/Sec 145.18 72.13 434.00 65.54%
    16392 requests in 30.08s, 64.94MB read
    Socket errors: connect 0, read 0, write 0, timeout 72
    Non-2xx or 3xx responses: 1
    Requests/sec: 545.00
    Transfer/sec: 2.16MB
    # Ratpack
    Running 30s test @ http://localhost:5050
    4 threads and 100 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 150.36ms 228.64ms 1.86s 88.18%
    Req/Sec 338.10 129.48 710.00 71.18%
    32746 requests in 30.08s, 127.09MB read
    Requests/sec: 1088.56
    Transfer/sec: 4.22MB

    View Slide


  50. # github.com/jruby/jruby/wiki/AboutJRuby
    # github.com/klappradla/jruby_ratpack_examples
    # blog.heroku.com/reactive_ruby_building_real_time_apps_with_jruby_and_ratpack

    View Slide