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

Adventures with Reactive Streams

Adventures with Reactive Streams

In today's world, more and more people are creating software that is expected to run at large scale. Large scale and cost-effectiveness often lead programmers to asynchronous programming models for handling vertical scalability concerns. Creating an asynchronous application on the JVM is nontrivial and often leads to disparate abstractions. Reactive Streams is one such abstraction that is widely accepted on the JVM today. This presentation is a deep dive into what it takes to implement the Reactive Streams specifications. It delves into various trade-offs that library developers have to consider while implementing Reactive Streams and which aspects of practical applications make such trade-offs easier.

Jo Voordeckers

October 25, 2018
Tweet

More Decks by Jo Voordeckers

Other Decks in Technology

Transcript

  1. Adventures with
    Reactive Streams
    @NiteshKant
    Nitesh Kant @jovoordeckers
    Jo Voordeckers

    View Slide

  2. Image source: https://interestingengineering.com/12-of-the-worlds-most-fascinating-dams

    View Slide

  3. Image source: https://en.wikipedia.org/wiki/Oroville_Dam_crisis

    View Slide

  4. @NiteshKant
    Nitesh Kant @jovoordeckers
    Jo Voordeckers

    View Slide

  5. Find my friends
    GET /friends?id=3 HTTP/1.1

    View Slide

  6. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    View Slide

  7. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    View Slide

  8. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    View Slide

  9. HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    Find my friends
    getFriendsCsv()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF
    … 011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101

    View Slide

  10. Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()

    View Slide

  11. Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()

    View Slide

  12. Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()

    View Slide

  13. Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()

    View Slide

  14. Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101 011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()

    View Slide

  15. Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    Producer
    Consumer
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()

    View Slide

  16. HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    Producer
    Consumer Control

    response.send()

    View Slide

  17. I am interested in consuming data!
    Control

    View Slide

  18. I am interested in consuming data!
    Give me 10 items!
    Control

    View Slide

  19. I am interested in consuming data!
    Give me 10 items!
    I am not interested any more.
    Control

    View Slide

  20. Java Message Service
    https://docs.oracle.com/javaee/5/tutorial/doc/bncdx.html
    // Synchronous
    Message m = consumer.receive();
    Message m = consumer.receive(1000); // time out 1000ms
    // Asynchronous
    MessageListener myListener = new MyListener(); // void onMessage(Message message)
    consumer.setMessageListener(myListener);
    request(1)

    View Slide

  21. Java Message Service
    https://docs.oracle.com/javaee/5/tutorial/doc/bncdx.html
    // Synchronous
    Message m = consumer.receive();
    Message m = consumer.receive(1000); // time out 1000ms
    // Asynchronous
    MessageListener myListener = new MyListener(); // void onMessage(Message message)
    consumer.setMessageListener(myListener);
    flow control depends on broker

    View Slide

  22. Apache Kafka
    https://kafka.apache.org/10/javadoc/?org/apache/kafka/clients/consumer/KafkaConsumer.html
    KafkaConsumer consumer = new KafkaConsumer<>(props);
    consumer.subscribe(Arrays.asList("foo", "bar"));
    while (true) {
    ConsumerRecords records = consumer.poll(100); // time out
    for (ConsumerRecord record : records) {
    // iterate over batch
    }
    consumer.commitSync();
    }
    // Flow control
    public void pause(java.util.Collection partitions)
    public void resume(java.util.Collection partitions)
    request(n)

    View Slide

  23. Apache Kafka
    https://kafka.apache.org/10/javadoc/?org/apache/kafka/clients/consumer/KafkaConsumer.html
    KafkaConsumer consumer = new KafkaConsumer<>(props);
    consumer.subscribe(Arrays.asList("foo", "bar"));
    while (true) {
    ConsumerRecords records = consumer.poll(100); // time out
    for (ConsumerRecord record : records) {
    // iterate over batch
    }
    consumer.commitSync();
    }
    // Flow control
    public void pause(java.util.Collection partitions)
    public void resume(java.util.Collection partitions)
    additional flow control
    by topic/partition

    View Slide

  24. Apache Kafka
    JMS
    // Synchronous
    Message m = consumer.receive();
    Message m = consumer.receive(1000);
    // Asynchronous
    // void onMessage(Message message)
    MessageListener myListener = new MyListener();
    consumer.setMessageListener(myListener);
    KafkaConsumer consumer = new KafkaConsumer<>(props);
    consumer.subscribe(Arrays.asList("foo", "bar"));
    while (true) {
    ConsumerRecords records = consumer.poll(100);
    for (ConsumerRecord record : records) {
    // iterate over batch
    }
    consumer.commitSync();
    }
    // Flow control
    public void pause(java.util.Collection partitions)
    public void resume(java.util.Collection partitions)

    View Slide

  25. Apache Kafka
    JMS
    // Synchronous
    Message m = consumer.receive();
    Message m = consumer.receive(1000);
    // Asynchronous
    // void onMessage(Message message)
    MessageListener myListener = new MyListener();
    consumer.setMessageListener(myListener);
    KafkaConsumer consumer = new KafkaConsumer<>(props);
    consumer.subscribe(Arrays.asList("foo", "bar"));
    while (true) {
    ConsumerRecords records = consumer.poll(100);
    for (ConsumerRecord record : records) {
    // iterate over batch
    }
    consumer.commitSync();
    }
    // Flow control
    public void pause(java.util.Collection partitions)
    public void resume(java.util.Collection partitions)
    how do we bridge
    these APIs?

    View Slide

  26. Service A Service B

    View Slide

  27. Service A Service B
    cache
    ?

    View Slide

  28. Service A Service B
    cache
    Service C
    ?

    View Slide

  29. Service A Service B
    cache
    Service C
    DB
    ?

    View Slide

  30. Service A Service B
    cache
    Service C
    DB
    ?
    define contract
    for interoperability

    View Slide

  31. Service A Service B
    cache
    Service C
    DB
    write adapters for
    all the things \o/
    ?

    View Slide

  32. Service A Service B
    cache
    Service C
    DB
    write adapters for
    all the things \o/
    ?
    ✓ cancelation
    ✓ buffering

    View Slide

  33. https://github.com/reactive-streams/reactive-streams-jvm

    View Slide

  34. https://github.com/reactive-streams/reactive-streams-jvm

    View Slide

  35. Reactive Streams
    public interface Publisher {
    public void subscribe(Subscriber super T> s);
    }

    View Slide

  36. Reactive Streams
    public interface Publisher {
    public void subscribe(Subscriber super T> s);
    }
    I am interested in consuming data!

    View Slide

  37. Reactive Streams
    public interface Subscriber {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
    }

    View Slide

  38. Reactive Streams
    public interface Subscriber {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
    }
    Control exchange

    View Slide

  39. Reactive Streams
    public interface Subscription {
    public void request(long n);
    public void cancel();
    }

    View Slide

  40. Reactive Streams
    public interface Subscription {
    public void request(long n);
    public void cancel();
    }
    Give me “n” items!

    View Slide

  41. Reactive Streams
    public interface Subscription {
    public void request(long n);
    public void cancel();
    }
    I am not interested any more.

    View Slide

  42. under-specification
    Image source: https://newrepublic.com/article/118416/what-dhaka-bangladesh-traffic-capital-world-can-teach-us

    View Slide

  43. under-specification
    risk of chaos between actors
    of the interaction rules
    Image source: https://newrepublic.com/article/118416/what-dhaka-bangladesh-traffic-capital-world-can-teach-us

    View Slide

  44. under-specification
    risk of chaos between actors
    target least common denominator
    of the interaction rules
    Image source: https://newrepublic.com/article/118416/what-dhaka-bangladesh-traffic-capital-world-can-teach-us

    View Slide

  45. under-specification
    risk of chaos between actors
    target least common denominator
    systemic inefficiency
    of the interaction rules
    Image source: https://newrepublic.com/article/118416/what-dhaka-bangladesh-traffic-capital-world-can-teach-us

    View Slide

  46. subscribe()
    Publisher Subscriber

    View Slide

  47. onSubscribe()
    subscribe()
    Publisher Subscription
    onSubscribe()
    Subscriber

    View Slide

  48. request()
    onSubscribe()
    subscribe()
    Publisher Subscription
    onSubscribe()
    Subscriber

    View Slide

  49. onNext()
    onComplete()
    onError()
    onSubscribe()
    subscribe()
    Publisher Subscription
    onNext()
    onComplete()
    onError()
    onSubscribe()
    Subscriber
    request()

    View Slide

  50. sequence
    onSubscribe() onComplete()
    subscribe()
    request()
    onSubscribe()
    subscribe() onError()
    request()
    onSubscribe()
    subscribe() onNext() onError()
    request()
    onSubscribe()
    subscribe() onNext() onNext() onComplete()
    request()
    request() cancel()
    onSubscribe()
    subscribe()
    request() cancel() onNext() onComplete()
    onSubscribe()
    subscribe()

    View Slide

  51. lifecycle management
    onNext()
    X
    subscribe()
    cancel()
    request()
    subscribe() onSubscribe() onNext() request()
    X
    onNext()
    onSubscribe()
    onNext()
    request()
    onComplete()
    X
    onError()
    subscribe() X

    View Slide

  52. How difficult could it
    be to implement?

    View Slide

  53. Single item,
    asynchronously produced
    and delivered

    View Slide

  54. Single item, asynchronously produced and delivered (Attempt #1)
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives

    View Slide

  55. Single item, asynchronously produced and delivered (Attempt #1)
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    emit()
    subscribe()
    request()
    cancel()

    View Slide

  56. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Asynchrony
    emit() subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  57. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Asynchrony
    emit()
    subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  58. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Asynchrony
    emit()
    subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  59. class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }
    Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Asynchrony
    emit()
    subscribe() request() cancel()

    View Slide

  60. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  61. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  62. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  63. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    X
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  64. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    https://github.com/reactive-streams/reactive-streams-jvm#1.3
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    s.onComplete();
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  65. Single item, asynchronously produced and delivered (Attempt #1)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    https://github.com/reactive-streams/reactive-streams-jvm#2.7
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    s.onComplete();
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  66. Single item, asynchronously produced and delivered (Attempt #2)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    s.onComplete();
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  67. Single item, asynchronously produced and delivered (Attempt #2)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    Concurrency
    emit()
    subscribe() request() cancel()
    class SingleValue implements Publisher {
    private T value;
    private boolean subscriberReady;
    private Subscriber super T> subscriber;
    @Override
    public synchronized void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (value != null) {
    s.onNext(value);
    s.onComplete();
    } else {
    subscriberReady = true;
    }
    }
    @Override
    public void cancel() {
    subscriberReady = false;
    }
    });
    }
    public synchronized void emit(T value) {
    if (subscriber != null && subscriberReady) {
    subscriber.onNext(value);
    } else {
    this.value = value;
    }
    }
    }

    View Slide

  68. Cost of synchronized?
    Image source: https://www.shutterstock.com/image-photo/iceberg-above-underwater-view-taken-greenland-1127373485

    View Slide

  69. s.onNext(value);
    public synchronized void emit(T value)
    ¯\_(ツ)_/¯

    View Slide

  70. Single item, asynchronously produced and delivered (Attempt #3)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    https://github.com/reactive-streams/reactive-streams-jvm#3.4

    View Slide

  71. class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndSet(REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    }
    });
    }
    public void emit(T value) {
    this.value = value;
    if (state.getAndSet(EMITTED) == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }
    Single item, asynchronously produced and delivered (Attempt #4)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    State Machine
    IDLE
    EMITTED
    REQUESTED

    View Slide

  72. Single item, asynchronously produced and delivered (Attempt #4)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    State Machine
    IDLE
    class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndSet(REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    }
    });
    }
    public void emit(T value) {
    this.value = value;
    if (state.getAndSet(EMITTED) == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }
    EMITTED
    REQUESTED

    View Slide

  73. Single item, asynchronously produced and delivered (Attempt #5)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    State Machine
    IDLE
    class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private static final int CANCELLED = 3;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndSet(REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    state.set(CANCELLED);
    }
    });
    }
    public void emit(T value) {
    this.value = value;
    if (state.getAndSet(EMITTED) == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }
    EMITTED
    REQUESTED
    CANCELLED

    View Slide

  74. class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private static final int CANCELLED = 3;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndSet(REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    state.set(CANCELLED);
    }
    });
    }
    public void emit(T value) {
    this.value = value;
    if (state.getAndSet(EMITTED) == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }
    Single item, asynchronously produced and delivered (Attempt #5)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    State Machine
    IDLE
    EMITTED
    REQUESTED
    CANCELLED

    View Slide

  75. Single item, asynchronously produced and delivered (Attempt #5)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    subscription.cancel();
    subscription.request(1)

    class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private static final int CANCELLED = 3;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndSet(REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    state.set(CANCELLED);
    }
    });
    }
    public void emit(T value) {
    this.value = value;
    if (state.getAndSet(EMITTED) == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }

    View Slide

  76. Single item, asynchronously produced and delivered (Attempt #6)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    State Machine
    IDLE
    class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    subscriber = s;
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndSet(REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    }
    });
    }
    public void emit(T value) {
    this.value = value;
    if (state.getAndSet(EMITTED) == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }
    EMITTED
    REQUESTED
    https://github.com/reactive-streams/reactive-streams-jvm#3.6

    View Slide

  77. Single item, asynchronously produced and delivered (Attempt #6)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private static final int CANCELLED = 3;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndUpdate(val -> val == CANCELLED ? CANCELLED : REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    state.set(CANCELLED);
    }
    });
    subscriber = s;
    }
    public void emit(T value) {
    this.value = value;
    int old = state.getAndUpdate(val -> val == CANCELLED ? CANCELLED : EMITTED);
    if (old == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }

    View Slide

  78. class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private static final int CANCELLED = 3;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    int old = state.getAndUpdate(val -> val == CANCELLED ? CANCELLED : REQUESTED);
    if (old == EMITTED) {
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    state.set(CANCELLED);
    }
    });
    subscriber = s;
    }
    public void emit(T value) {
    this.value = value;
    int old = state.getAndUpdate(val -> val == CANCELLED ? CANCELLED : EMITTED);
    if (old == REQUESTED) {
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }
    Single item, asynchronously produced and delivered (Attempt #6)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives

    View Slide

  79. Single item, asynchronously produced and delivered (Attempt #6)
    * This is a hot/eager source, i.e. the work has started before a Subscriber arrives
    class SingleValue implements Publisher {
    private static final int IDLE = 0;
    private static final int REQUESTED = 1;
    private static final int EMITTED = 2;
    private static final int TERMINATED = 3;
    private T value;
    private Subscriber super T> subscriber;
    private final AtomicInteger state = new AtomicInteger(IDLE);
    @Override
    public void subscribe(Subscriber super T> s) {
    s.onSubscribe(new Subscription() {
    @Override
    public void request(long n) {
    if (n <= 0 && state.getAndSet(TERMINATED) != TERMINATED) {
    s.onError(new IllegalArgumentException("Non positive request signals are illegal."));
    return;
    }
    int old = state.getAndUpdate(val -> val == TERMINATED ? TERMINATED : REQUESTED);
    if (old == EMITTED) {
    state.set(TERMINATED);
    s.onNext(value);
    s.onComplete();
    }
    }
    @Override
    public void cancel() {
    state.set(TERMINATED);
    }
    });
    subscriber = s;
    }
    public void emit(T value) {
    this.value = value;
    int old = state.getAndUpdate(val -> val == TERMINATED ? TERMINATED : EMITTED);
    if (old == REQUESTED) {
    state.set(TERMINATED);
    subscriber.onNext(value);
    subscriber.onComplete();
    }
    }
    }
    Want to see how multiple item emission
    will look like?

    View Slide

  80. Let’s get real …

    View Slide

  81. response.send()
    Find my friends
    GET /friends?id=3 HTTP/1.1
    getFriendsCsv()
    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101 011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    011101100
    101110011
    101100101
    110011100
    101110111
    011001101
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    View Slide

  82. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    View Slide

  83. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher

    View Slide

  84. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    Control

    View Slide

  85. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    subscription.request(1)

    View Slide

  86. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    subscription.request(1)
    Demand is required to compose
    through multiple components

    View Slide

  87. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    subscription.cancel()
    Cancellation is required to compose
    through multiple components

    View Slide

  88. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    Publisher client.get("friends?id=1")
    response.send(Publisher resp)

    View Slide

  89. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    response.send(
    client.get("friends?id=1")
    );

    View Slide

  90. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    List transformToJson(List csvs) {
    List friends;
    for (String csv : csvs) {
    friends.add(toJson(csv));
    }
    return friends;
    }

    View Slide

  91. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    response.send(
    client.get("friends?id=1")
    );

    View Slide

  92. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    response.send(
    client.get("friends?id=1")
    .map(csv -> toJson(csv))
    );

    View Slide

  93. Find my friends
    GET /friends?id=3 HTTP/1.1 getFriendsCsv()
    transformToJson()
    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    response.send()
    HTTP/1.1 200 OK
    Nitesh, Kant, SF
    Jo, Voordeckers, SF

    HTTP/1.1 200 OK
    {First: Nitesh, Last: Kant, Location: SF}
    {First: Jo, Last: Voordeckers, Location: SF}

    Socket
    Socket
    Subscriber
    Publisher
    response.send(
    client.get("friends?id=1")
    .map(csv -> toJson(csv))
    );
    Function composition.

    View Slide

  94. Reactive Streams is
    not sufficient
    as an end-user API.

    View Slide

  95. Function Composition
    Lack of standards
    Project Reactor
    RxJava
    JDK Streams
    Akka Streams
    Kafka Streams

    View Slide

  96. Practically, most applications
    have blocking code.

    View Slide

  97. https://github.com/reactive-streams/reactive-streams-jvm#2.2

    View Slide

  98. https://github.com/reactive-streams/reactive-streams-jvm#2.2
    Embracing this reality is necessary…

    View Slide

  99. Not everything is a stream
    Publisher getUser(String id);

    View Slide

  100. Not everything is a stream
    Publisher getUser(String id);
    Publisher fireAndForget(String log);

    View Slide

  101. Not everything is a stream
    Publisher getUser(String id);

    Publisher fireAndForget(String log);
    Publisher request(HttpRequest request);

    View Slide

  102. Reactive Streams
    HTTP Kafka
    Cassandra
    RPC Redis
    ()
    Function Composition
    Not everything is a stream
    Blocking safety

    View Slide

  103. Image source: http://sciencemeetsfood.org/team-work/

    View Slide

  104. Thank You!
    @NiteshKant
    Nitesh Kant @jovoordeckers
    Jo Voordeckers
    +

    View Slide