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

Architecture découplée grâce aux Reactive Extensions

David
April 20, 2016

Architecture découplée grâce aux Reactive Extensions

Auparavant, les applications se connectaient à une seule base de données. Aujourd’hui, elles doivent communiquer avec un ensemble de base de données et composer avec des services web distants. Elles ne sont plus des blocs monolithiques, mais distribuées sur différents serveurs sur différentes zones géographiques. Elles sont “scalables” mais elles doivent maintenant attendre les réponses d’autres applications.

Comment profiter de ces temps d’attente ? Comment casser ce couplage temporel ? Comment transformer un couplage applicatif fort en couplage lâche ?

Cette université fera le tour de RxJava et RxJs. Comment les mettre en place sur un projet et dans une équipe. Et surtout comment utiliser ces bibliothèques pour découpler votre architecture.

University - 20 Avril 2016 - Devoxx France (Palais des congrès de Paris)

David Wursteisen - Brice Dutheil

David

April 20, 2016
Tweet

More Decks by David

Other Decks in Programming

Transcript

  1. #DevoxxFR #Rx
    Architecture Découplée
    grâce aux Reactive Extensions
    @BriceDutheil @dwursteisen
    Mercredi 20 Avril - Amphi bleu - 9h30

    View full-size slide

  2. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous allons voir

    View full-size slide

  3. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous allons voir
    Reactive Extensions
    en théorie

    View full-size slide

  4. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous allons voir
    Reactive Extensions
    en théorie
    en pratique

    View full-size slide

  5. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous allons voir
    Reactive Extensions
    en théorie
    en pratique
    sur notre application

    View full-size slide

  6. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous allons voir
    Reactive Extensions
    en théorie
    en pratique
    sur notre application
    Pause

    View full-size slide

  7. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous
    ne verrons pas

    View full-size slide

  8. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous ne verrons pas
    Énumération des opérateurs

    View full-size slide

  9. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous ne verrons pas
    Énumération des opérateurs
    Mieux que ces alternatives ?

    View full-size slide

  10. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce que nous ne verrons pas
    Énumération des opérateurs
    Mieux que ces alternatives ?
    Expliquer tous les patterns
    d’utilisation possible

    View full-size slide

  11. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Qui sommes nous ?

    View full-size slide

  12. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Indép’
    Ingénierie
    logicielle

    View full-size slide

  13. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Formation
    Conseil
    Consultant

    View full-size slide

  14. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    https://youtu.be/TT8TLS2Ac0o

    View full-size slide

  15. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    #DevoxxFR #Rx

    View full-size slide

  16. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Êtes-vous familier avec
    RxJava ?

    View full-size slide

  17. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Êtes-vous familier avec RxJava ?
    Oui Non

    View full-size slide

  18. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Êtes-vous familier avec RxJava ?
    Oui

    View full-size slide

  19. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Êtes-vous familier avec RxJava ?
    Non

    View full-size slide

  20. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Architecture Découplée
    grâce aux Reactive Extensions

    View full-size slide

  21. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Le couplage temporel

    View full-size slide

  22. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Application typique
    war
    tomcat

    View full-size slide

  23. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous le
    fonctionnement de
    Tomcat ?

    View full-size slide

  24. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous Tomcat ?
    Oui Non

    View full-size slide

  25. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous Tomcat ?
    Oui

    View full-size slide

  26. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous Tomcat ?
    Non

    View full-size slide

  27. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Examinons le
    cheminement
    d’une requête HTTP

    View full-size slide

  28. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    client
    nouvelle
    requête

    View full-size slide

  29. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    client OS
    Négociation TCP
    nouvelle
    requête

    View full-size slide

  30. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    connexion établie
    prête à être
    consommée

    View full-size slide

  31. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    Accepte la
    requête
    connexion établie
    prête à être
    consommée
    acceptedCount =

    View full-size slide

  32. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    connexion établie
    prête à être
    consommée
    Accepte la
    requête
    Requête donnée aux
    threads de travail si
    slot disponible
    Worker
    Executor
    maxThreads =

    View full-size slide

  33. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    connexion établie
    prête à être
    consommée
    Accepte la
    requête
    Requête donnée aux
    threads de travail si
    slot disponible
    Thread

    View full-size slide

  34. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    connexion établie
    prête à être
    consommée
    Accepte la
    requête
    Requête donnée aux
    threads de travail si
    slot disponible
    Thread
    w
    a
    r
    Lit la
    payload
    war

    View full-size slide

  35. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    connexion établie
    prête à être
    consommée
    Accepte la
    requête
    Requête donnée aux
    threads de travail si
    slot disponible
    Thread
    w
    a
    r
    Lit la
    payload
    Business
    war

    View full-size slide

  36. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    connexion établie
    prête à être
    consommée
    Accepte la
    requête
    Requête donnée aux
    threads de travail si
    slot disponible
    Thread
    w
    a
    r
    Lit la
    payload
    Écrit la réponse,
    ferme la
    connexion
    Business
    war

    View full-size slide

  37. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / BIO
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    connexion établie
    prête à être
    consommée
    Accepte la
    requête
    Requête donnée aux
    threads de travail si
    slot disponible
    Thread
    war
    Lit la
    payload
    Écrit la réponse,
    ferme la
    connexion
    Business

    View full-size slide

  38. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Premier constat
    Files d’attente
    OS

    View full-size slide

  39. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Un thread
    par requête

    View full-size slide

  40. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Plus de
    thread
    Plus gros
    hardware

    View full-size slide

  41. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Plus de
    thread
    Plus
    de serveurs

    View full-size slide

  42. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Application typique
    war
    tomcat
    service tiers

    View full-size slide

  43. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avec une
    base de données

    View full-size slide

  44. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat
    client OS
    Négociation TCP
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    connexion établie
    prête à être
    consommée
    Accepte la
    requête
    Requête donnée aux
    threads de travail si
    slot disponible
    Thread
    w
    a
    r
    Lit la
    payload
    Écrit la réponse,
    ferme la
    connexion
    Business
    war

    View full-size slide

  45. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Client
    Nouvelle
    requête
    Thread
    war
    Temps

    View full-size slide

  46. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Client
    Nouvelle
    requête
    Thread
    war
    Plus de requêtes en base
    Plus long à répondre

    View full-size slide

  47. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Client
    Nouvelle
    requête
    Thread
    webservice.api
    microservice #
    war
    Avec d’autres dépendances

    View full-size slide

  48. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat
    client OS
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    Attend un slot
    disponible
    Thread
    war
    Executor
    full

    View full-size slide

  49. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Point de vue du CPU
    Pas d’instruction à exécuter
    Le système attend sur des I/Os

    View full-size slide

  50. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Deuxième observation :
    Couplage temporel

    View full-size slide

  51. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    On attend
    Services distants
    Base de données
    Fournisseurs tiers

    View full-size slide

  52. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Localement aussi
    Lecture/Écriture sur disque
    - ex : swap
    Panne hardware
    - ex : disque en panne augmente la latence

    View full-size slide

  53. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Solutions ?

    View full-size slide

  54. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Augmenter le
    nombre de
    thread Tomcat

    View full-size slide

  55. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Utiliser d’autres Executor

    View full-size slide

  56. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    C’est toujours bloquant
    et ça peut devenir
    complexe

    View full-size slide

  57. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Revient à
    augmenter
    le nombre
    de thread

    View full-size slide

  58. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Sur Tomcat, utiliser un
    autre connecteur ?
    NIO, APR, NIO2 (Tomcat 8)

    View full-size slide

  59. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    NIO ne résout pas le
    problème de fond
    §9.2 The Container Provider should ensure that the
    dispatch of the request to a target servlet occurs in
    the same thread of the same JVM as the original
    request.
    http://download.oracle.com/otn-pub/jcp/servlet-3.0-mrel-full-oth-JSpec/servlet-3_0-mrel-spec.pdf

    View full-size slide

  60. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / NIO
    client OS
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    Thread
    Poller
    Thread
    Requête #
    war

    View full-size slide

  61. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Tomcat / NIO
    client OS
    Requête #
    nouvelle
    requête
    Acceptor
    Thread
    Thread
    Poller
    Thread
    Requête #
    war

    View full-size slide

  62. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ne pas oublier
    le tuning

    View full-size slide

  63. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ne pas oublier
    le tuning
    mais…

    View full-size slide

  64. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comprendre la JVM

    View full-size slide

  65. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Long à établir

    View full-size slide

  66. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Change avec
    la charge / le business

    View full-size slide

  67. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Dans tous
    les cas
    Tomcat

    View full-size slide

  68. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Dans tous
    les cas
    Notre application

    View full-size slide

  69. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View full-size slide

  70. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de
    notre application

    View full-size slide

  71. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de notre application
    • Executors
    • Future

    View full-size slide

  72. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de notre application
    • Executors
    • Future
    • Embarquer une techno à la ActiveMQ ?

    View full-size slide

  73. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de notre application
    • Executors
    • Future
    • Embarquer une techno à la ActiveMQ ?
    • Problème de lourdeur, overhead

    View full-size slide

  74. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de notre application
    • Executors
    • Future
    • Embarquer une techno à la ActiveMQ ?
    • Problème de lourdeur, overhead
    • Quid de la composition

    View full-size slide

  75. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de notre application
    • Executors
    • Future
    • Embarquer une techno à la ActiveMQ ?
    • Problème de lourdeur, overhead
    • Quid de la composition
    • CompletableFuture
    => Avec Collections ou Streams ?

    View full-size slide

  76. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de notre application
    • Executors
    • Future
    • Embarquer une techno à la ActiveMQ ?
    • Problème de lourdeur, overhead
    • Quid de la composition
    • CompletableFuture
    => Avec Collections ou Streams ?

    View full-size slide

  77. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Améliorer le code de notre application
    • Executors
    • Future
    • Embarquer une techno à la ActiveMQ ?
    • Problème de lourdeur, overhead
    • Quid de la composition
    • CompletableFuture
    => Avec Collections ou Streams ?
    • Gestion d’erreurs

    View full-size slide

  78. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Le code pour mitiger
    ces problèmes est
    complexe

    View full-size slide

  79. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Le code pour mitiger
    ces problèmes est plus
    obscur au raisonnement

    View full-size slide

  80. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avez vous déjà rencontré ces problèmes ?
    Oui Non

    View full-size slide

  81. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avez vous déjà rencontré ces problèmes ?
    Non

    View full-size slide

  82. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avez vous déjà rencontré ces problèmes ?
    Oui

    View full-size slide

  83. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Quelles solutions ?
    Tuning
    Tomcat
    Pool JDBC

    Changement
    du code

    View full-size slide

  84. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Quelles solutions ?
    Tuning
    Tomcat
    Pool JDBC

    View full-size slide

  85. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Quelle solutions ?
    Changement
    du code

    View full-size slide

  86. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Reactive Extensions
    pour mieux utiliser les
    ressources hardware

    View full-size slide

  87. #DevoxxFR #Rx
    Reactive Extensions
    En théorie

    View full-size slide

  88. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique

    View full-size slide

  89. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique

    View full-size slide

  90. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique
    .NET
    Java
    JavaScript

    View full-size slide

  91. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique
    .NET
    Java
    JavaScript
    Scala
    Clojure
    Swift

    View full-size slide

  92. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique

    View full-size slide

  93. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pourquoi faire ?
    Une API pour la
    programmation
    asynchrone

    View full-size slide

  94. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Appel Synchrone - Asynchrone
    Appel synchrone
    versus
    Appel asynchrone

    View full-size slide

  95. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Appel Synchrone
    Client
    Serveur

    View full-size slide

  96. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Appel Synchrone
    Client
    Serveur
    Appel bloquant

    View full-size slide

  97. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Appel Asynchrone
    Client
    Serveur

    View full-size slide

  98. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Appel Asynchrone
    Exécution d’autres
    traitements
    Client
    Serveur

    View full-size slide

  99. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Temporalité
    http://blog.codinghorror.com/the-infinite-space-between-words/
    Temps machine Temps humain
    1 cycle CPU 0.3 nanosecondes 1 seconde
    Accès disque (SSD) 50-150 microsecondes 2-6 jours
    Accès disque
    (mécanique)
    1-10 millisecondes 1-12 mois
    Envoi d’un paquet de
    San Francisco à New
    York
    40 milliseconds 4 ans

    View full-size slide

  100. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Temporalité
    http://blog.codinghorror.com/the-infinite-space-between-words/
    Temps machine Temps humain
    1 cycle CPU 0.3 nanosecondes 1 seconde
    Accès disque (SSD) 50-150 microsecondes 2-6 jours
    Accès disque
    (mécanique)
    1-10 millisecondes 1-12 mois
    Envoi d’un paquet de
    San Francisco à New
    York
    40 milliseconds 4 ans

    View full-size slide

  101. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?

    View full-size slide

  102. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    Future ?
    Callback ?

    View full-size slide

  103. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    Future future = …
    future.get(); // bloquant !

    View full-size slide

  104. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    future1.get();
    future2.get();
    future3.get();
    future4.get();
    future5.get();
    Ordonnancement optimal ?

    View full-size slide

  105. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    Future ?
    Callback ?

    View full-size slide

  106. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    }
    });

    View full-size slide

  107. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    }
    });
    }
    });

    View full-size slide

  108. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    }
    });
    }
    });

    View full-size slide

  109. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    client.execute(new Callback() {
    @Override
    public void completed(HttpResponse response) {
    }
    });
    }
    });
    Callback hell

    View full-size slide

  110. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour quoi faire ?
    Future ?
    Callback ?

    View full-size slide

  111. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comprendre les concepts
    Les technologies passent.
    Les concepts restent.

    View full-size slide

  112. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Concepts applicables
    pour d’autres
    bibliothèques de
    type Reactive Streams

    View full-size slide

  113. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Back to basics

    View full-size slide

  114. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJava permet de manipuler des
    évènements d’une manière
    synchrone et/ou asynchrone

    View full-size slide

  115. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Flux d’évènements fini
    Diagramme Marble

    View full-size slide

  116. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Flux d’évènements fini
    Évènements Fin du flux

    View full-size slide

  117. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Flux d’évènements avec une erreur
    Évènements Erreur

    View full-size slide

  118. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Flux d’évènements infini
    Évènements

    View full-size slide

  119. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Flux fini sans évènement
    Fin du flux

    View full-size slide

  120. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Quelle est la nature de
    ces évènements ?

    View full-size slide

  121. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    json json json
    Observable

    View full-size slide

  122. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    λ ϕ φ
    json json json
    Observable
    Observable

    View full-size slide

  123. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    λ ϕ φ
    json json json
    Observable
    Observable
    Observable

    View full-size slide

  124. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comment écouter ces
    évènements ?

    View full-size slide

  125. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observer

    View full-size slide

  126. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    OnNext* (OnCompleted|OnError)?

    View full-size slide

  127. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    OnNext* (OnCompleted|OnError)?

    View full-size slide

  128. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    OnNext* (OnCompleted|OnError)?

    View full-size slide

  129. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    OnNext* (OnCompleted|OnError)?

    View full-size slide

  130. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .subscribe(new Observer() {
    @Override
    public void onNext(Integer v) {
    System.out.println("Valeur : " + v);
    }
    @Override
    public void onCompleted() {
    System.out.println("Fin");
    }
    @Override
    public void onError(Throwable e) {
    System.out.println("Erreur");
    }
    });

    View full-size slide

  131. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .subscribe(new Observer() {
    @Override
    public void onNext(Integer v) {
    System.out.println("Valeur : " + v);
    }
    @Override
    public void onCompleted() {
    System.out.println("Fin");
    }
    @Override
    public void onError(Throwable e) {
    System.out.println("Erreur");
    }
    });

    View full-size slide

  132. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .subscribe(new Observer() {
    @Override
    public void onNext(Integer v) {
    System.out.println("Valeur : " + v);
    }
    @Override
    public void onCompleted() {
    System.out.println("Fin");
    }
    @Override
    public void onError(Throwable e) {
    System.out.println("Erreur");
    }
    });

    View full-size slide

  133. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .subscribe(new Observer() {
    @Override
    public void onNext(Integer v) {
    System.out.println("Valeur : " + v);
    }
    @Override
    public void onCompleted() {
    System.out.println("Fin");
    }
    @Override
    public void onError(Throwable e) {
    System.out.println("Erreur");
    }
    });

    View full-size slide

  134. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .subscribe(v-> System.out.println("Valeur : " + v),
    e -> System.out.println("Erreur"),
    () -> System.out.println("Fin")
    );

    View full-size slide

  135. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .subscribe(v-> System.out.println("Valeur : " + v),
    e -> System.out.println("Erreur"),
    () -> System.out.println("Fin")
    );
    onNext
    onError
    onCompleted

    View full-size slide

  136. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comment manipuler ces
    évènements ?

    View full-size slide

  137. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable

    View full-size slide

  138. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Transformation à base
    d’opérateurs.

    View full-size slide

  139. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .map(i -> i * 2)
    .take(2)
    .defaultIfEmpty(0)
    .subscribe();

    View full-size slide

  140. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .map(i -> i * 2)
    .take(2)
    .defaultIfEmpty(0)
    .subscribe();
    Opérateur map

    View full-size slide

  141. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .map(i -> i * 2)
    .take(2)
    .defaultIfEmpty(0)
    .subscribe();
    Opérateur take

    View full-size slide

  142. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .map(i -> i * 2)
    .take(2)
    .defaultIfEmpty(0)
    .subscribe();
    Opérateur
    defaultIfEmpty

    View full-size slide

  143. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Liste des opérateurs
    disponibles sur
    reactivex.io

    View full-size slide

  144. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Question :
    Comment convertir une liste de
    mots en minuscules et filtrer
    pour garder uniquement les
    mots de plus de 3 lettres ?

    View full-size slide

  145. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just("bjr", "DevoXx")
    .map(str -> str.toLowerCase())
    .filter(str -> str.length() > 3)
    .subscribe(System.out::println);

    View full-size slide

  146. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just("bjr", "DevoXx")
    .map(str -> str.toLowerCase())
    .filter(str -> str.length() > 3)
    .subscribe(System.out::println);
    Conversion

    View full-size slide

  147. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just("bjr", "DevoXx")
    .map(str -> str.toLowerCase())
    .filter(str -> str.length() > 3)
    .subscribe(System.out::println);
    Filtre

    View full-size slide

  148. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just("bjr", "DevoXx")
    .map(str -> str.toLowerCase())
    .filter(str -> str.length() > 3)
    .subscribe(System.out::println);
    Observable 1

    View full-size slide

  149. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just("bjr", "DevoXx")
    .map(str -> str.toLowerCase())
    .filter(str -> str.length() > 3)
    .subscribe(System.out::println);
    Observable 2

    View full-size slide

  150. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just("bjr", "DevoXx")
    .map(str -> str.toLowerCase())
    .filter(str -> str.length() > 3)
    .subscribe(System.out::println);
    Observable 3

    View full-size slide

  151. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comprendre les concepts
    Manipuler une
    monade

    View full-size slide

  152. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comprendre les concepts

    View full-size slide

  153. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Concept de Monade
    Une structure ayant
    - Un type paramétré (Observable)
    - Une factory (Observable.just(...))
    - Une méthode flatMap (obs.flatMap(...))
    - Structure programmatique
    (Grossièrement)

    View full-size slide

  154. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Concept de Monade
    Stream Java 8

    View full-size slide

  155. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    List words = Stream.of("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .collect(Collectors.toList());
    Factory

    View full-size slide

  156. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    List words = Stream.of("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .collect(Collectors.toList());
    Étape 1

    View full-size slide

  157. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    List words = Stream.of("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .collect(Collectors.toList());
    Étape 2

    View full-size slide

  158. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    List words = Stream.of("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .collect(Collectors.toList()); Étape 3
    (fonction terminale)

    View full-size slide

  159. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Concept de Monade
    Observable RxJava

    View full-size slide

  160. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    Observable.just("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .subscribe();
    Factory

    View full-size slide

  161. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    Observable.just("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .subscribe();
    Étape 1

    View full-size slide

  162. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    Observable.just("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .subscribe();
    Étape 2

    View full-size slide

  163. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    Observable.just("bonJour", "bonjour", "Hello")
    .map(str -> str.toLowerCase())
    .distinct()
    .subscribe(); Étape 3
    (fonction terminale)

    View full-size slide

  164. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avec les Reactive Extensions,
    nous allons principalement
    manipuler des Observables

    View full-size slide

  165. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    Observable
    =
    Monade

    View full-size slide

  166. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Structure programmatique
    Observable
    =
    Programmation
    fonctionnelle

    View full-size slide

  167. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Évitez les effets de bord
    Structure programmatique
    une fonction est dite à effet de bord si elle
    modifie un état autre que sa valeur de retour

    View full-size slide

  168. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Évitez les effets de bord
    Structure programmatique
    une fonction est dite à effet de bord si elle
    modifie un état autre que sa valeur de retour
    (Comme avec les
    streams Java 8)

    View full-size slide

  169. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Question :
    Comment créer une liste
    à partir d’un ensemble
    de valeurs ?

    View full-size slide

  170. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Effets de bord
    List result = new ArrayList<>();
    Observable.just(1, 2, 3)
    .map(i -> result.add(i))
    .subscribe();

    View full-size slide

  171. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    List result = new ArrayList<>();
    Observable.just(1, 2, 3)
    .map(i -> result.add(i))
    .subscribe();
    Effets de bord
    Effet de bord

    View full-size slide

  172. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .toList()
    .subscribe(result -> {/* ... */});
    Effets de bord
    Pas d’effet de bord

    View full-size slide

  173. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .toList()
    .subscribe(result -> {/* ... */});
    Effets de bord
    Consommation de
    la liste

    View full-size slide

  174. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Question :
    Comment logger une
    opération ?

    View full-size slide

  175. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Effets de bord
    Observable.just(1, 2, 3)
    .map(i -> {
    LOGGER.info("value : " + i);
    return i;
    })
    .subscribe();

    View full-size slide

  176. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .map(i -> {
    LOGGER.info("value : " + i);
    return i;
    })
    .subscribe();
    Effets de bord
    Effet de bord

    View full-size slide

  177. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Évitez les effets de bord
    (ou soyez explicite)

    View full-size slide

  178. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Effets de bord
    Observable.just(1, 2, 3)
    // explicite
    .doOnNext(i -> LOGGER.info("Valeur :" + i))
    .subscribe();

    View full-size slide

  179. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Effets de bord
    Observable.just(1, 2, 3)
    .doOnSubscribe(() -> LOGGER.info("Subscribe"))
    .doOnNext(i -> LOGGER.info("Valeur :" + i))
    .doOnTerminate(() -> LOGGER.info("Terminate"))
    .subscribe();

    View full-size slide

  180. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Effets de bord
    Observable.just(1, 2, 3)
    .doOnSubscribe(() -> LOGGER.info("Subscribe"))
    .doOnNext(i -> LOGGER.info("Valeur :" + i))
    .doOnTerminate(() -> LOGGER.info("Terminate"))
    .subscribe();

    View full-size slide

  181. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Effets de bord
    Observable.just(1, 2, 3)
    .doOnSubscribe(() -> LOGGER.info("Subscribe"))
    .doOnNext(i -> LOGGER.info("Valeur :" + i))
    .doOnTerminate(() -> LOGGER.info("Terminate"))
    .subscribe();

    View full-size slide

  182. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Effets de bord
    Observable.just(1, 2, 3)
    .doOnSubscribe(() -> LOGGER.info("Subscribe"))
    .doOnNext(i -> LOGGER.info("Valeur :" + i))
    .doOnTerminate(() -> LOGGER.info("Terminate"))
    .subscribe();

    View full-size slide

  183. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Question :
    Comment compter le
    nombre d’erreur de
    différents Observables ?

    View full-size slide

  184. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    // attention ! état partagé !
    AtomicLong errors = new AtomicLong(0);
    Observable.just(1, 2, 3)
    .doOnError(ex -> errors.incrementAndGet())
    .subscribe();

    View full-size slide

  185. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    // attention ! état partagé !
    AtomicLong errors = new AtomicLong(0);
    Observable.just(1, 2, 3)
    .doOnError(ex -> errors.incrementAndGet())
    .subscribe();

    View full-size slide

  186. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Question :
    Comment créer des
    Observables ?

    View full-size slide

  187. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comment créer des Observables
    Observable.just()
    Observable.fromCallable()
    Observable.defer()
    Observable.using()
    Observable.create()
    Complexité

    View full-size slide

  188. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comment créer des Observables
    Observable.just()
    Observable.fromCallable()
    Observable.defer()
    Observable.using()
    Observable.create()
    Simple
    d’utilisation

    View full-size slide

  189. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comment créer des Observables
    Observable.just()
    Observable.fromCallable()
    Observable.defer()
    Observable.using()
    Observable.create() Complexe
    d’utilisation

    View full-size slide

  190. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Comment créer des Observables
    Observable.just()
    Observable.fromCallable()
    Observable.defer()
    Observable.using()
    Observable.create() Complexe
    d’utilisation
    Offre un maximum de contrôle

    View full-size slide

  191. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Quelle méthode pour
    quelle utilisation ?

    View full-size slide

  192. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(compute())
    .subscribe();

    View full-size slide

  193. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(compute())
    .subscribe();

    View full-size slide

  194. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(compute())
    .subscribe();
    Appelé
    immédiatement

    View full-size slide

  195. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    int result = compute();
    Observable.just(result)
    .subscribe();

    View full-size slide

  196. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    int result = compute();
    Observable.just(result)
    .subscribe();

    View full-size slide

  197. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just permet
    d'émettre une valeur
    déjà existante.

    View full-size slide

  198. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.defer(() -> Observable.just(compute()))
    .subscribe();

    View full-size slide

  199. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.defer(() -> Observable.just(compute()))
    .subscribe();

    View full-size slide

  200. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.defer(() -> Observable.just(compute()))
    .subscribe();
    Création tardive

    View full-size slide

  201. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.defer(() -> Observable.just(compute()))
    .subscribe();
    Création tardive
    Création d’un Observable ?

    View full-size slide

  202. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.defer permet
    de créer tardivement un
    Observable.

    View full-size slide

  203. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.fromCallable(() -> compute())
    .subscribe();

    View full-size slide

  204. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.fromCallable(() -> compute())
    .subscribe();
    Création tardive

    View full-size slide

  205. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.fromCallable
    permet d'émettre
    tardivement une valeur.

    View full-size slide

  206. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using(
    () -> new DB(),
    db -> Observable.just(db.doQuery()),
    db -> db.closeDb())
    .subscribe();

    View full-size slide

  207. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using(
    () -> new DB(),
    db -> Observable.just(db.doQuery()),
    db -> db.closeDb())
    .subscribe();
    Création d’une ressource

    View full-size slide

  208. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using(
    () -> new DB(),
    db -> Observable.just(db.doQuery()),
    db -> db.closeDb())
    .subscribe();
    Émission d’un
    résultat

    View full-size slide

  209. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using(
    () -> new DB(),
    db -> Observable.just(db.doQuery()),
    db -> db.closeDb())
    .subscribe();
    Fermeture de la
    ressource

    View full-size slide

  210. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using permet
    d'associer un Observable
    à une ressource.

    View full-size slide

  211. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Attention
    Zone Dangereuse !

    View full-size slide

  212. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    subscriber.add(/* ... */);
    subscriber.setProducer(n -> {
    subscriber.onNext(/* ... */);
    // ...
    subscriber.onCompleted();
    });
    }).subscribe();

    View full-size slide

  213. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    subscriber.add(/* ... */);
    subscriber.setProducer(n -> {
    subscriber.onNext(/* ... */);
    // ...
    subscriber.onCompleted();
    });
    }).subscribe();
    ?
    ?
    ?

    View full-size slide

  214. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    subscriber.add(/* ... */);
    subscriber.setProducer(n -> {
    subscriber.onNext(/* ... */);
    // ...
    subscriber.onCompleted();
    });
    }).subscribe();
    Désabonnement
    Backpressure
    Contrat Rx

    View full-size slide

  215. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    subscriber.onNext(compute());
    subscriber.onCompleted();
    }).subscribe();

    View full-size slide

  216. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    subscriber.onNext(compute());
    subscriber.onCompleted();
    }).subscribe();
    Contrat Rx

    View full-size slide

  217. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.fromCallable(() -> compute())
    .subscribe();
    Plus simple !

    View full-size slide

  218. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    for (int i = 0; i < 10; i++) {
    if (!subscriber.isUnsubscribed()) {
    subscriber.onNext(compute(i));
    }
    }
    subscriber.onCompleted();
    }).subscribe();

    View full-size slide

  219. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    for (int i = 0; i < 10; i++) {
    if (!subscriber.isUnsubscribed()) {
    subscriber.onNext(compute(i));
    }
    }
    subscriber.onCompleted();
    }).subscribe();
    Le flux est-il encore
    actif ?
    Éviter de lancer ce
    calcul (coûteux)

    View full-size slide

  220. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.range(1, 10)
    .map(i -> compute(i))
    .subscribe(System.out::println);
    Plus simple !

    View full-size slide

  221. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    DB db = new DB();
    subscriber.add(Subscriptions.create(() -> db.closeDb()));
    subscriber.onNext(db);
    subscriber.onCompleted();
    }).subscribe();

    View full-size slide

  222. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    DB db = new DB();
    subscriber.add(Subscriptions.create(() -> db.closeDb()));
    subscriber.onNext(db);
    subscriber.onCompleted();
    }).subscribe(); Code de
    désabonnement

    View full-size slide

  223. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using(
    () -> new DB(),
    db -> Observable.just(db.doQuery()),
    db -> db.closeDb())
    .subscribe();
    Plus simple !

    View full-size slide

  224. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create
    permet de gérer
    le contrat Rx
    et le désabonnement
    et la backpressure

    View full-size slide

  225. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create
    vous oblige à gérer
    le contrat Rx
    et le désabonnement
    et la backpressure

    View full-size slide

  226. #DevoxxFR #Rx
    Reactive Extensions
    En pratique

    View full-size slide

  227. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous d’autres
    modèles de concurrence ?

    View full-size slide

  228. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous d’autres modèles de
    concurrence ?
    Non
    Thread
    uniquement
    Oui
    Acteur, STM,
    Channels

    View full-size slide

  229. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous vous d’autres modèles de
    concurrence ?
    Non
    Thread
    uniquement

    View full-size slide

  230. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Connaissez vous vous d’autres modèles de
    concurrence ?
    Oui
    Acteur, STM,
    Channels

    View full-size slide

  231. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pour explorer
    d’autres
    modèles
    de concurrence

    View full-size slide

  232. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Modèle de concurrence

    View full-size slide

  233. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    On a vu Tomcat et les servlets
    OS
    Tomcat / BIO
    client
    Requête #
    Acceptor
    Thread
    Thread
    war

    View full-size slide

  234. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Modèle de concurrence
    de RxJava

    View full-size slide

  235. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }

    View full-size slide

  236. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }
    Travail sur le
    Thread courant

    View full-size slide

  237. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Par défaut synchrone*
    method() {
    Observable.from(items)
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }
    Travail sur le
    Thread courant

    View full-size slide

  238. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJava permet un contrôle
    explicite de la concurrence
    avec observeOn() ou
    avec subscribeOn()

    View full-size slide

  239. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }
    Thread courant

    View full-size slide

  240. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .observeOn( )
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }
    Thread courant

    View full-size slide

  241. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .observeOn( )
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }
    Thread courant

    View full-size slide

  242. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .observeOn(Schedulers.computation())
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }
    Thread courant
    Travail planifié sur
    computation

    View full-size slide

  243. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    observeOn() change le
    contexte des opérations
    qui suivent

    View full-size slide

  244. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Il peut y avoir plusieurs
    observeOn()

    View full-size slide

  245. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Par défaut synchrone*
    method() {
    Observable.from(items)
    .map(this::transform)
    .delay(10, SECONDS))
    .subscribe(response::resume, response::resume);
    }
    Travail sur le
    Thread courant
    * Certains opérateurs fonctionnent par défaut sur un autre Scheduler

    View full-size slide

  246. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Par défaut synchrone*
    method() {
    Observable.from(items)
    .map(this::transform)
    .delay(10, SECONDS))
    .subscribe(response::resume, response::resume);
    }
    Travail sur le
    Thread courant
    * Certains opérateurs fonctionnent par défaut sur un autre Scheduler
    Change le contexte

    View full-size slide

  247. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Certains opérateurs ont
    le même effet que
    observeOn()

    View full-size slide

  248. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .observeOn(Schedulers.computation())
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribe(response::resume, response::resume);
    }
    Thread courant
    Travail planifié sur
    computation

    View full-size slide

  249. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .observeOn(Schedulers.computation())
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribeOn( )
    .subscribe(response::resume, response::resume);
    }
    Thread courant
    Travail planifié sur
    computation

    View full-size slide

  250. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .observeOn(Schedulers.computation())
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribeOn( )
    .subscribe(response::resume, response::resume);
    }
    Thread courant
    Travail planifié sur
    computation

    View full-size slide

  251. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    method() {
    Observable.from(items)
    .observeOn(Schedulers.computation())
    .map(this::transform)
    .flatMap(this::computeRelativeItems)
    .subscribeOn(Schedulers.io())
    .subscribe(response::resume, response::resume);
    }
    Thread courant
    Travail planifié sur
    computation
    Production des
    éléments sur io

    View full-size slide

  252. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    subscribeOn() définit le
    contexte où s’exécute la
    production des éléments

    View full-size slide

  253. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Il ne peut y avoir
    qu’un seul
    subscribeOn()
    Premier arrivé, premier servi !

    View full-size slide

  254. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    2 principaux modèles de
    schedulers

    View full-size slide

  255. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    computation()
    .map(str -> …) Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .map(str -> …)

    View full-size slide

  256. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    computation()
    Nombre de
    coeur CPU
    .map(str -> …) Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .map(str -> …)

    View full-size slide

  257. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    computation()
    Nombre de
    coeur CPU
    .debounce(…)
    .filter(e -> ...)
    .merge(...)
    Élément #
    .filter(…)
    Élément <>
    .merge(…)

    View full-size slide

  258. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Le modèle de
    computation() est une
    boucle d’évènements

    View full-size slide

  259. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Augmente le rendement
    du CPU

    View full-size slide

  260. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Thread.sleep()
    CountDownLatch.await()
    for(;;) { /* do work */ }
    I/O

    View full-size slide

  261. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Thread.sleep()
    CountDownLatch.await()
    for(;;) { /* do work */ }
    I/O
    NON

    View full-size slide

  262. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ne PAS bloquer
    la boucle d’évènements

    View full-size slide

  263. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    io()
    Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .flatMap(…)

    View full-size slide

  264. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    io()
    DB
    Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .flatMap(…)

    View full-size slide

  265. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    io()
    DB
    Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .flatMap(…)

    View full-size slide

  266. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    io()
    DB
    Network
    Internet
    Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .flatMap(…)

    View full-size slide

  267. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    io()
    DB
    Network
    Internet
    Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .flatMap(…)

    View full-size slide

  268. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    io()
    DB
    Network
    Internet
    Élément #
    .filter(…)
    Élément <>
    .merge(…)
    Élément ‘a’
    .flatMap(…)

    View full-size slide

  269. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Le modèle du scheduler
    io() est un pool de thread
    qui grossit au besoin

    View full-size slide

  270. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    io() ne bloque pas le CPU

    View full-size slide

  271. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avec JAX-RS

    View full-size slide

  272. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET
    @Path("{heavyness}")
    public Response wait(@PathParam("heavyness") int heavyness) throws InterruptedException {
    System.out.format("heavy work that will take %dms%n", heavyness);
    MILLISECONDS.sleep(heavyness); // hard and long work
    return Response.ok(format("Waited %dms", heavyness)).build();
    }
    }

    View full-size slide

  273. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET
    @Path("{heavyness}")
    public Response wait(@PathParam("heavyness") int heavyness) throws InterruptedException {
    System.out.format("heavy work that will take %dms%n", heavyness);
    MILLISECONDS.sleep(heavyness); // hard and long work
    return Response.ok(format("Waited %dms", heavyness)).build();
    }
    }
    Travail

    View full-size slide

  274. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    executor.submit(() -> {
    try {
    MILLISECONDS.sleep(heavyness);
    ar.resume(format("Waited %dms", heavyness));
    } catch (InterruptedException e) {
    Thread.interrupted();
    ar.resume(e);
    }
    });
    }
    }

    View full-size slide

  275. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    executor.submit(() -> {
    try {
    MILLISECONDS.sleep(heavyness);
    ar.resume(format("Waited %dms", heavyness));
    } catch (InterruptedException e) {
    Thread.interrupted();
    ar.resume(e);
    }
    });
    }
    }
    JAX-RS 2.0 (Servlet 3.0)

    View full-size slide

  276. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    executor.submit(() -> {
    try {
    MILLISECONDS.sleep(heavyness);
    ar.resume(format("Waited %dms", heavyness));
    } catch (InterruptedException e) {
    Thread.interrupted();
    ar.resume(e);
    }
    });
    }
    }
    JAX-RS 2.0 (Servlet 3.0)
    Tache
    asynchrone

    View full-size slide

  277. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    executor.submit(() -> {
    try {
    MILLISECONDS.sleep(heavyness);
    ar.resume(format("Waited %dms", heavyness));
    } catch (InterruptedException e) {
    Thread.interrupted();
    ar.resume(e);
    }
    });
    }
    }
    JAX-RS 2.0 (Servlet 3.0)
    thread pool
    Tache
    asynchrone

    View full-size slide

  278. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    executor.submit(() -> {
    try {
    MILLISECONDS.sleep(heavyness);
    ar.resume(format("Waited %dms", heavyness));
    } catch (InterruptedException e) {
    Thread.interrupted();
    ar.resume(e);
    }
    });
    }
    }
    JAX-RS 2.0 (Servlet 3.0)
    thread pool
    Tache
    asynchrone
    response.resume() pour
    retourner la réponse HTTP

    View full-size slide

  279. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    JAX-RS et Rx

    View full-size slide

  280. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    response.setTimeout(50, MILLISECONDS);
    Observable.just(waitTime)
    .observeOn(Schedulers.computation())
    .map(this::longProcess)
    .subscribe(result -> ar.resume(result),
    throwable -> ar.resume(throwable));
    }
    private String longProcess(int heavyness) {
    ...
    }
    }

    View full-size slide

  281. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    response.setTimeout(50, MILLISECONDS);
    Observable.just(waitTime)
    .observeOn(Schedulers.computation())
    .map(this::longProcess)
    .subscribe(result -> ar.resume(result),
    throwable -> ar.resume(throwable));
    }
    private String longProcess(int heavyness) {
    ...
    }
    }
    Traitement asynchrone
    avec Rx

    View full-size slide

  282. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    response.setTimeout(50, MILLISECONDS);
    Observable.just(waitTime)
    .observeOn(Schedulers.computation())
    .map(this::longProcess)
    .subscribe(result -> ar.resume(result),
    throwable -> ar.resume(throwable));
    }
    private String longProcess(int heavyness) {
    ...
    }
    }
    Prend les paramètres

    View full-size slide

  283. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    response.setTimeout(50, MILLISECONDS);
    Observable.just(waitTime)
    .observeOn(Schedulers.computation())
    .map(this::longProcess)
    .subscribe(result -> ar.resume(result),
    throwable -> ar.resume(throwable));
    }
    private String longProcess(int heavyness) {
    ...
    }
    }
    Scheduler sur lequel faire le traitement
    ≈≈> executor

    View full-size slide

  284. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    response.setTimeout(50, MILLISECONDS);
    Observable.just(waitTime)
    .observeOn(Schedulers.computation())
    .map(this::longProcess)
    .subscribe(result -> ar.resume(result),
    throwable -> ar.resume(throwable));
    }
    private String longProcess(int heavyness) {
    ...
    }
    }
    Sera exécuté sur
    un Computation thread
    Thread de la servlet

    View full-size slide

  285. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    response.setTimeout(50, MILLISECONDS);
    Observable.just(waitTime)
    .observeOn(Schedulers.computation())
    .map(this::longProcess)
    .subscribe(result -> ar.resume(result),
    throwable -> ar.resume(throwable));
    }
    private String longProcess(int heavyness) {
    ...
    }
    }
    Travail

    View full-size slide

  286. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @Path("heavy-stuff")
    public static class WaitResource {
    @GET @Path("{heavyness}")
    public void wait(@Suspended AsyncResponse ar, @PathParam("heavyness") int heavyness) {
    response.setTimeout(50, MILLISECONDS);
    Observable.just(waitTime)
    .observeOn(Schedulers.computation())
    .map(this::longProcess)
    .subscribe(result -> ar.resume(result),
    throwable -> ar.resume(throwable));
    }
    private String longProcess(int heavyness) {
    ...
    }
    }
    onNext : résultat du traitement
    onError : termine la requête HTTP avec une
    erreur

    View full-size slide

  287. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Traitement toujours long
    =
    Attente pour le client

    View full-size slide

  288. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Traitement toujours long
    =
    Attente pour le client
    =
    Toujours besoin de threads

    View full-size slide

  289. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    asyncResponse.setTimeout(50, MILLISECONDS);
    Retourne 503 Service Unavailable

    View full-size slide

  290. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    asyncResponse.setTimeout(50, MILLISECONDS);
    Retourne 503 Service Unavailable
    MAIS le travail en cours est toujours actif

    View full-size slide

  291. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Introduire un TimeoutHandler
    Status HTTP
    Headers
    Entité personnalisée
    Arrêt / interruption des traitements
    ...

    View full-size slide

  292. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    JAX-RS apporte des
    fonctionnalités riches
    mapping, routage, filtre,

    View full-size slide

  293. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    … mais limite
    l’intégration avec RxJava,
    par les contraintes de la
    spec.

    View full-size slide

  294. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    JAX-RS nous limite
    dans notre capacité
    à découpler

    View full-size slide

  295. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Faut-il sortir de la stack
    JavaEE ?

    View full-size slide

  296. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Netflix, Spotify, Twitter,
    Uber, d’autres sont allés
    dans cette direction.

    View full-size slide

  297. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    L’architecture
    microservices est une
    opportunité pour
    explorer les alternatives

    View full-size slide

  298. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Par exemple en Java,
    Vert.x, RxNetty, …

    View full-size slide

  299. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty.createHttpServer(port, (request, response) -> {
    if (request.getHttpMethod() == HttpMethod.POST) {
    return request.getContent()
    .map(TehServer::parseBody)
    .map(TehServer::longStuff)
    .flatMap(result -> {
    response.setStatus(HttpResponseStatus.OK);
    response.writeString(result);
    return response.close();
    }).ignoreElements();
    }
    return response.close(false);
    });

    View full-size slide

  300. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty.createHttpServer(port, (request, response) -> {
    if (request.getHttpMethod() == HttpMethod.POST) {
    return request.getContent()
    .map(TehServer::parseBody)
    .map(TehServer::longStuff)
    .flatMap(result -> {
    response.setStatus(HttpResponseStatus.OK);
    response.writeString(result);
    return response.close();
    }).ignoreElements();
    }
    return response.close(false);
    });
    Créer un serveur

    View full-size slide

  301. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty.createHttpServer(port, (request, response) -> {
    if (request.getHttpMethod() == HttpMethod.POST) {
    return request.getContent()
    .map(TehServer::parseBody)
    .map(TehServer::longStuff)
    .flatMap(result -> {
    response.setStatus(HttpResponseStatus.OK);
    response.writeString(result);
    return response.close();
    }).ignoreElements();
    }
    return response.close(false);
    });
    Handler pour gérer
    la requête

    View full-size slide

  302. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty.createHttpServer(port, (request, response) -> {
    if (request.getHttpMethod() == HttpMethod.POST) {
    return request.getContent()
    .map(TehServer::parseBody)
    .map(TehServer::longStuff)
    .flatMap(result -> {
    response.setStatus(HttpResponseStatus.OK);
    response.writeString(result);
    return response.close();
    }).ignoreElements();
    }
    return response.close(false);
    });
    Retourne un Observable

    View full-size slide

  303. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty.createHttpServer(port, (request, response) -> {
    if (request.getHttpMethod() == HttpMethod.POST) {
    return request.getContent()
    .map(TehServer::parseBody)
    .map(TehServer::longStuff)
    .flatMap(result -> {
    response.setStatus(HttpResponseStatus.OK);
    response.writeString(result);
    return response.close();
    }).ignoreElements();
    }
    return response.close(false);
    });
    Travail sur la request
    avec RxJava

    View full-size slide

  304. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty s’utilise pour
    des services très simples
    websocket, http, tcp, …

    View full-size slide

  305. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty intégre RxJava
    au plus bas niveau

    View full-size slide

  306. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Un main() seulement

    View full-size slide

  307. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxNetty offre une API de
    bas niveau pour plus
    de contrôle

    View full-size slide

  308. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    … mais demande un effort
    appréciable sur la mise en
    oeuvre des aspects d’une
    API HTTP publique

    View full-size slide

  309. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Services composés

    View full-size slide

  310. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API
    Service B
    Service A

    View full-size slide

  311. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API

    View full-size slide

  312. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    }
    Exemple : un stub JAX-RS

    View full-size slide

  313. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .subscribe(response::resume);
    }
    Un Observable qui
    renvoie quelque chose
    sur AsyncResponse

    View full-size slide

  314. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {

    })
    .subscribe(response::resume);
    }
    Ici seront fait les appels

    View full-size slide

  315. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API
    Service A

    View full-size slide

  316. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Response aResponse = wsA(lastNumber);

    })
    .subscribe(response::resume);
    }
    Appel
    au service A

    View full-size slide

  317. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs =
    Observable.fromCallable(() -> wsA(lastNumber));

    })
    .subscribe(response::resume);
    }
    Appel
    observable
    au service A

    View full-size slide

  318. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs =
    Observable.fromCallable(() -> wsA(lastNumber))
    .map(r -> r.readEntity(String.class));

    })
    .subscribe(response::resume);
    }
    Transformation
    de la payload

    View full-size slide

  319. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API
    Service B
    Service A

    View full-size slide

  320. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsA(lastNumber))
    .map(r -> r.readEntity(String.class));
    Observable bObs =
    Observable.fromCallable(() -> wsB(lastNumber))
    .map(r -> r.readEntity(String.class));

    })
    .subscribe(response::resume);
    }
    Appel observable
    au service B

    View full-size slide

  321. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API
    Service B
    Service A

    View full-size slide

  322. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsA(lastNumber))
    .map(r -> r.readEntity(String.class));
    Observable bObs = Observable.fromCallable(() -> wsB(lastNumber))
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs,
    (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume);
    }
    Composition
    de A et de B

    View full-size slide

  323. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Si une exception est
    produite ?

    View full-size slide

  324. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsA(lastNumber))
    .map(r -> r.readEntity(String.class));
    Observable bObs = Observable.fromCallable(() -> wsB(lastNumber))
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    response::resume);
    }
    Ajout d’un handler onError

    View full-size slide

  325. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Planifier les appels
    externes sur
    Schedulers.io()

    View full-size slide

  326. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsA(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class));
    Observable bObs = Observable.fromCallable(() -> wsB(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    response::resume);
    }
    Appels réseau
    exécutés sur
    des threads dédiés
    aux I/O

    View full-size slide

  327. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API
    Service B
    Service A
    503

    View full-size slide

  328. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsA(lastNumber))
    .subscribeOn(Schedulers.io())
    .flatMap(r -> {
    if (r.getStatus() == 503) {
    return Observable.error(
    new ServiceUnavailable("service A"));
    }
    return just(r.readEntity(String.class));
    });
    Observable bObs = Observable.fromCallable(() -> wsB(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    response::resume);
    }
    Gestion du statut HTTP 503

    View full-size slide

  329. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsServiceA(lastNumber))
    .subscribeOn(Schedulers.io())
    .flatMap(r -> {
    if (r.getStatus() != 200) {
    return Observable.error(
    new ServiceUnavailable("service A"));
    }
    return Observable.just(r.readEntity(String.class));
    });
    Observable bObs = Observable.fromCallable(() -> wsServiceB(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    (error) -> {
    response.resume(error);
    });
    }
    AsyncReponse.resume(Throwable)
    ⇒ 500 Server Error

    View full-size slide

  330. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsServiceA(lastNumber))
    .subscribeOn(Schedulers.io())
    .flatMap(r -> {
    if (r.getStatus() != 200) {
    return Observable.error(new ServiceUnavailable("service A"));
    }
    return Observable.just(r.readEntity(String.class));
    });
    Observable bObs = Observable.fromCallable(() -> wsServiceB(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    (error) -> {
    response.resume(Response.serverError()
    .entity(error.getMessage())
    .build());
    });
    }
    Personnalisation de la
    payload d’erreur

    View full-size slide

  331. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsServiceA(lastNumber))
    .subscribeOn(Schedulers.io())
    .flatMap(r -> {
    if (r.getStatus() != 200) {
    return Observable.error(new ServiceUnavailable("service A"));
    }
    return Observable.just(r.readEntity(String.class));
    });
    Observable bObs = Observable.fromCallable(() -> wsServiceB(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    (error) -> {
    response.resume(Response.status(((HttpServiceEx) error).httpStatus)
    .entity(error.getMessage())
    .build());
    });
    }
    Propagation du statut HTTP

    View full-size slide

  332. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Recommencer
    l’appel en cas d’erreur ?

    View full-size slide

  333. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeInterestingValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsServiceA(lastNumber))
    .subscribeOn(Schedulers.io())
    .flatMap(r -> {
    if (r.getStatus() != 200) {
    return Observable.error(new ServiceUnavailable("service A"));
    }
    return Observable.just(r.readEntity(String.class));
    })
    .retry(2);
    Observable bObs = Observable.fromCallable(() -> wsServiceB(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    (error) -> {
    response.resume(Response.status(((HttpServiceException) error).proposedHttpStatus)
    .entity(error.getMessage())
    .build());
    });
    }
    Recommencera 2 fois

    View full-size slide

  334. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Quand une dépendance
    est hors-délai ?

    View full-size slide

  335. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API
    Service B
    Service A
    Service B

    View full-size slide

  336. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> makeValue())
    .flatMap(lastNumber -> {
    Observable aObs = Observable.fromCallable(() -> wsServiceA(lastNumber))
    .subscribeOn(Schedulers.io())
    .flatMap(r -> {
    if (r.getStatus() != 200) {
    return Observable.error(new ServiceUnavailable("service A"));
    }
    return Observable.just(r.readEntity(String.class));
    })
    .retry(2);
    Observable bObs = Observable.fromCallable(() -> wsServiceB(lastNumber))
    .subscribeOn(Schedulers.io())
    .map(r -> r.readEntity(String.class))
    .timeout(500, MILLISECONDS,
    error(new ServiceTimeout("service B")));
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    (error) -> {
    response.resume(Response.status(((HttpServiceException) error).proposedHttpStatus)
    .entity(error.getMessage())
    .build());
    });
    }
    Défini un délai acceptable

    View full-size slide

  337. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    C’est beaucoup
    de code technique !

    View full-size slide

  338. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Hystrix permet
    de résoudre
    ces challenges
    de façon plus pertinente

    View full-size slide

  339. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> new SecureRandom().nextInt(1000))
    .flatMap(lastNumber -> {
    Observable aObs = new ServiceACommand(lastNumber).observe();
    Observable bObs = new ServiceBCommand(lastNumber).observe();
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    (error) -> {
    response.resume(Response.statusError()
    .entity(error.getMessage())
    .build());
    });
    }
    Commandes Hystrix

    View full-size slide

  340. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Exécution immédiate et
    asynchrone avec
    .observe()
    Hot

    View full-size slide

  341. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Exécution retardée jusqu’à
    l'abonnement avec
    .toObservable()
    Cold

    View full-size slide

  342. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Une commande Hystrix
    ne doit jamais partir
    en erreur

    View full-size slide

  343. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    @GET public void wait(@Suspended final AsyncResponse response) {
    Observable.fromCallable(() -> new SecureRandom().nextInt(1000))
    .flatMap(lastNumber -> {
    Observable aObs = new ServiceACommand(lastNumber).observe();
    Observable bObs = new ServiceBCommand(lastNumber).observe();
    return Observable.zip(aObs, bObs, (a, b) -> format("=> Result : %s, %s", a, b);
    })
    .subscribe(response::resume,
    (error) -> {
    response.resume(Response.serverError()
    .entity(error.getMessage())
    .build());
    });
    }
    Erreur 500

    View full-size slide

  344. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    class ServiceACommand extends HystrixObservableCommand {
    private int number;
    protected ServiceACommand(int number) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("work group"))
    .andCommandKey(HystrixCommandKey.Factory.asKey("work"))
    .andCommandPropertiesDefaults(
    HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));
    this.number = number;
    }
    @Override
    protected Observable construct() {
    return Observable.fromCallable(() -> wsServiceB(number))
    .map(response -> response.readEntity(String.class));
    }
    @Override
    protected Observable resumeWithFallback() {
    return Observable.just("Service A too long");
    }
    }

    View full-size slide

  345. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    class ServiceACommand extends HystrixObservableCommand {
    private int number;
    protected ServiceACommand(int number) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("work group"))
    .andCommandKey(HystrixCommandKey.Factory.asKey("work"))
    .andCommandPropertiesDefaults(
    HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));
    this.number = number;
    }
    @Override
    protected Observable construct() {
    return Observable.fromCallable(() -> wsServiceB(number))
    .map(response -> response.readEntity(String.class));
    }
    @Override
    protected Observable resumeWithFallback() {
    return Observable.just("Service A too long");
    }
    }
    Commande Hystrix
    Type de retour

    View full-size slide

  346. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    class ServiceACommand extends HystrixObservableCommand {
    private int number;
    protected ServiceACommand(int number) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("work group"))
    .andCommandKey(HystrixCommandKey.Factory.asKey("work"))
    .andCommandPropertiesDefaults(
    HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));
    this.number = number;
    }
    @Override
    protected Observable construct() {
    return Observable.fromCallable(() -> wsServiceB(number))
    .map(response -> response.readEntity(String.class));
    }
    @Override
    protected Observable resumeWithFallback() {
    return Observable.just("Service A too long");
    }
    }
    Commande Hystrix
    observable
    Construction

    View full-size slide

  347. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    class ServiceACommand extends HystrixObservableCommand {
    private int number;
    protected ServiceACommand(int number) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("work group"))
    .andCommandKey(HystrixCommandKey.Factory.asKey("work"))
    .andCommandPropertiesDefaults(
    HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));
    this.number = number;
    }
    @Override
    protected Observable construct() {
    return Observable.fromCallable(() -> wsServiceB(number))
    .map(response -> response.readEntity(String.class));
    }
    @Override
    protected Observable resumeWithFallback() {
    return Observable.just("Service A too long");
    }
    }
    Appel observable

    View full-size slide

  348. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    class ServiceACommand extends HystrixObservableCommand {
    private int number;
    protected ServiceACommand(int number) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("work group"))
    .andCommandKey(HystrixCommandKey.Factory.asKey("work"))
    .andCommandPropertiesDefaults(
    HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));
    this.number = number;
    }
    @Override
    protected Observable construct() {
    return Observable.fromCallable(() -> wsServiceB(number))
    .map(response -> response.readEntity(String.class));
    }
    @Override
    protected Observable resumeWithFallback() {
    return Observable.just("Service A too long");
    }
    }
    Plan de secours
    En cas d’erreur

    View full-size slide

  349. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    class ServiceACommand extends HystrixObservableCommand {
    private int number;
    protected ServiceACommand(int number) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("work group"))
    .andCommandKey(HystrixCommandKey.Factory.asKey("work"))
    .andCommandPropertiesDefaults(
    HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)));
    this.number = number;
    }
    @Override
    protected Observable construct() {
    return Observable.fromCallable(() -> wsServiceB(number))
    .map(response -> response.readEntity(String.class));
    }
    @Override
    protected Observable resumeWithFallback() {
    return Observable.just("Service A too long");
    }
    }
    Personnalisation des paramètres
    de la commande

    View full-size slide

  350. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Le coupe-circuit de
    Hystrix

    View full-size slide

  351. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Composite
    API
    Service B
    Service A

    View full-size slide

  352. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Fermé, les requêtes
    passent

    View full-size slide

  353. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ouvert, la dépendance
    en erreur est isolée sur
    une période de temps

    View full-size slide

  354. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avertir un client lorsque
    le circuit est ouvert

    View full-size slide

  355. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    void executeCommand(HystrixObservableCommand command) {
    command.observe()
    .subscribe(
    result -> Response.ok(result).build(),
    throwable -> {
    if (throwable instanceof HystrixRuntimeException) {
    if (((HystrixRuntimeException) throwable).getFailureType() == FailureType.SHORTCIRCUIT) {
    Response.status(Status.SERVICE_UNAVAILABLE)
    .header(HttpHeaders.RETRY_AFTER,
    command.getProperties()
    .circuitBreakerSleepWindowInMilliseconds()
    .get() / 1000);
    }
    }
    Response.serverError().build();
    });
    }
    Pour une commande Hystrix

    View full-size slide

  356. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    void executeCommand(HystrixObservableCommand command) {
    command.observe()
    .subscribe(
    result -> Response.ok(result).build(),
    throwable -> {
    if (throwable instanceof HystrixRuntimeException) {
    if (((HystrixRuntimeException) throwable).getFailureType() == FailureType.SHORTCIRCUIT) {
    Response.status(Status.SERVICE_UNAVAILABLE)
    .header(HttpHeaders.RETRY_AFTER,
    command.getProperties()
    .circuitBreakerSleepWindowInMilliseconds()
    .get() / 1000);
    }
    }
    Response.serverError().build();
    });
    }
    Si le problème vient de la
    commande Hystrix

    View full-size slide

  357. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    private void executeCommand(HystrixObservableCommand command) {
    command.observe()
    .subscribe(
    result -> Response.ok(result).build(),
    throwable -> {
    if (throwable instanceof HystrixRuntimeException) {
    if (((HystrixRuntimeException) throwable).getFailureType()
    == FailureType.SHORTCIRCUIT) {
    Response.status(Status.SERVICE_UNAVAILABLE)
    .header(HttpHeaders.RETRY_AFTER,
    command.getProperties()
    .circuitBreakerSleepWindowInMilliseconds()
    .get() / 1000);
    }
    }
    Response.serverError().build();
    });
    }
    Et que le circuit est ouvert

    View full-size slide

  358. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    private void executeCommand(HystrixObservableCommand command) {
    command.observe()
    .subscribe(
    result -> Response.ok(result).build(),
    throwable -> {
    if (throwable instanceof HystrixRuntimeException) {
    if (((HystrixRuntimeException) throwable).getFailureType() == FailureType.SHORTCIRCUIT) {
    Response.status(Status.SERVICE_UNAVAILABLE)
    .header(HttpHeaders.RETRY_AFTER,
    command.getProperties()
    .circuitBreakerSleepWindowInMilliseconds()
    .get() / 1000);
    }
    }
    Response.serverError().build();
    });
    }
    Alors
    proposer au client un prochain créneau

    View full-size slide

  359. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    private void executeCommand(HystrixObservableCommand command) {
    command.observe()
    .subscribe(
    result -> Response.ok(result).build(),
    throwable -> {
    if (throwable instanceof HystrixRuntimeException) {
    if (((HystrixRuntimeException) throwable).getFailureType() == FailureType.SHORTCIRCUIT) {
    Response.status(Status.SERVICE_UNAVAILABLE)
    .header(HttpHeaders.RETRY_AFTER,
    command.getProperties()
    .circuitBreakerSleepWindowInMilliseconds()
    .get() / 1000);
    }
    }
    Response.serverError().build();
    });
    }

    View full-size slide

  360. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Hystrix demande une
    certaine dose de code
    Il est possible d’utiliser
    des annotations avec
    hystrix-javanica

    View full-size slide

  361. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View full-size slide

  362. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Hystrix protège un
    système distribué de
    dépendances en erreur
    ou hors-délai

    View full-size slide

  363. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Hystrix offre
    une variété d’outils

    View full-size slide

  364. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View full-size slide

  365. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Autre piste à explorer

    View full-size slide

  366. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Pression arrière

    View full-size slide

  367. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Production
    Consommation

    View full-size slide

  368. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Producteur Consommateur ?

    View full-size slide

  369. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Producteur Consommateur ?

    View full-size slide

  370. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Consommation
    .buffer()
    Production

    View full-size slide

  371. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Consommation
    .sample()
    Production

    View full-size slide

  372. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Consommation
    Isolation du
    consommateur
    Production

    View full-size slide

  373. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Consommation
    Pression arrière
    Isolation du
    consommateur
    Production

    View full-size slide

  374. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    C’est le temps d’une pause
    Posez nous des questions
    directement ou via Twitter

    View full-size slide

  375. #DevoxxFR #Rx
    Reactive Extensions
    Sur notre application

    View full-size slide

  376. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Leçons apprises
    en utilisant les
    Reactive Extensions ?

    View full-size slide

  377. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJava est-il
    la solution à tout ?

    View full-size slide

  378. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJava est-il
    la solution à tout ?
    NON !

    View full-size slide

  379. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Les Streams Java 8
    peuvent être plus
    intéressants.

    View full-size slide

  380. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Il est possible
    de faire cohabiter
    RxJava et Streams Java8

    View full-size slide

  381. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3, 4)
    .toList()
    .map(list -> {
    return list.stream()
    .filter(i -> i % 2 == 0)
    .collect(Collectors.toList());
    }).subscribe();

    View full-size slide

  382. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3, 4)
    .toList()
    .map(list -> {
    return list.stream()
    .filter(i -> i % 2 == 0)
    .collect(Collectors.toList());
    }).subscribe();

    View full-size slide

  383. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3, 4)
    .toList()
    .map(list -> {
    return list.stream()
    .filter(i -> i % 2 == 0)
    .collect(Collectors.toList());
    }).subscribe();

    View full-size slide

  384. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    List> obs = new ArrayList<>();
    obs.add(Observable.defer(() -> Observable.just(1, 2, 3)));
    obs.add(Observable.just(4, 5, 6));
    obs.add(Observable.fromCallable(() -> 7));
    Observable.merge(obs).subscribe();

    View full-size slide

  385. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    List> obs = new ArrayList<>();
    obs.add(Observable.defer(() -> Observable.just(1, 2, 3)));
    obs.add(Observable.just(4, 5, 6));
    obs.add(Observable.fromCallable(() -> 7));
    Observable.merge(obs).subscribe();

    View full-size slide

  386. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    List> obs = new ArrayList<>();
    obs.add(Observable.defer(() -> Observable.just(1, 2, 3)));
    obs.add(Observable.just(4, 5, 6));
    obs.add(Observable.fromCallable(() -> 7));
    Observable.merge(obs).subscribe();

    View full-size slide

  387. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    List> obs = new ArrayList<>();
    obs.add(Observable.defer(() -> Observable.just(1, 2, 3)));
    obs.add(Observable.just(4, 5, 6));
    obs.add(Observable.fromCallable(() -> 7));
    Observable.merge(obs).subscribe();

    View full-size slide

  388. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ce n’est pas parce
    que l’on peut le faire
    que l’on doit le faire.

    View full-size slide

  389. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable feeds = Observable.merge(
    services.stream()
    .map(service -> service.newRequest().user(user).all().observe())
    .map(feedObservable -> feedObservable
    .doOnError(throwable -> log.error(throwable.getMessage(), throwable))
    .onErrorResumeNext(Observable.empty()))
    .collect(Collectors.toList()));
    feeds.subscribe();

    View full-size slide

  390. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable feeds = Observable.merge(
    services.stream()
    .map(service -> service.newRequest().user(user).all().observe())
    .map(feedObservable -> feedObservable
    .doOnError(throwable -> log.error(throwable.getMessage(), throwable))
    .onErrorResumeNext(Observable.empty()))
    .collect(Collectors.toList()));
    feeds.subscribe();
    RxJava
    Stream Java 8

    View full-size slide

  391. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Les lambdas simplifient
    la lecture du code

    View full-size slide

  392. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxView.clickEvents(tapButton)
    .doOnNext(new Action1() {
    @Override
    public void call(ViewClickEvent onClickEvent) {
    LOGGER.debug("--------- GOT A TAP");
    }
    })
    .map(new Func1() {
    @Override
    public Integer call(ViewClickEvent onClickEvent) {
    return 1;
    }
    }).subscribe();

    View full-size slide

  393. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxView.clickEvents(tapButton)
    .doOnNext(new Action1() {
    @Override
    public void call(ViewClickEvent onClickEvent) {
    LOGGER.debug("--------- GOT A TAP");
    }
    })
    .map(new Func1() {
    @Override
    public Integer call(ViewClickEvent onClickEvent) {
    return 1;
    }
    }).subscribe();
    Code technique

    View full-size slide

  394. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxView.clickEvents(tapButton)
    .doOnNext(event -> LOGGER.debug("--------- GOT A TAP"))
    .map(event -> 1)
    .subscribe();
    3 fois moins de code !

    View full-size slide

  395. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Sur Android,
    vous pouvez utiliser
    Kotlin ou Retrolambda
    ou Java 8 (Jack&Jill)

    View full-size slide

  396. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    https://twitter.com/Piwai/status/717755657106001921

    View full-size slide

  397. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }).subscribe();

    View full-size slide

  398. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }).subscribe();

    View full-size slide

  399. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }).subscribe();

    View full-size slide

  400. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }).subscribe();

    View full-size slide

  401. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }).subscribe();

    View full-size slide

  402. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }).subscribe();
    Trop complexe !

    View full-size slide

  403. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }).subscribe();
    Extraction

    View full-size slide

  404. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> transform(i))
    .subscribe();
    public Observable transform(int i) {
    Observable complex = webService.complexify(i)
    .map(str -> str.toLowerCase())
    .retry(4);
    Observable human = webService.toHumanString(i)
    .filter(str -> str.length() < 3)
    .take(1)
    .onErrorResumeNext(Observable.empty())
    .defaultIfEmpty("Oups !");
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr);
    }

    View full-size slide

  405. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .flatMap(i -> transform(i))
    .subscribe();
    public Observable transform(int i) {
    Observable complex = fetchComplexify(i);
    Observable human = fetchHuman(i);
    return Observable.zip(complex, human, (c, h) -> c + h)
    .flatMap(str -> webService.frequencyOf(str))
    .flatMapIterable(itr -> itr)
    }

    View full-size slide

  406. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ne quittez pas la monade !
    (grossièrement)

    View full-size slide

  407. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ne quittez pas la monade !
    Observable.just(1, 2, 3)
    .subscribe(arg -> {
    webservice.call(arg).subscribe(System.out::println);
    });

    View full-size slide

  408. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.just(1, 2, 3)
    .subscribe(arg -> {
    webservice.call(arg).subscribe(System.out::println);
    });
    Ne quittez pas la monade !
    Observable imbriqué

    View full-size slide

  409. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ne quittez pas la monade !
    Observable.just(1, 2, 3)
    .flatMap(arg -> webservice.call(arg))
    .subscribe(System.out::println);

    View full-size slide

  410. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Ne quittez pas la monade !
    Observable.just(1, 2, 3)
    .flatMap(arg -> webservice.call(arg))
    .subscribe(System.out::println);

    View full-size slide

  411. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    flatMap permet
    d'émettre zéro, un,
    ou plusieurs évènements

    View full-size slide

  412. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println);

    View full-size slide

  413. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println);

    View full-size slide

  414. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println);

    View full-size slide

  415. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    flatMap ne remplace pas
    un Observable par un
    autre.

    View full-size slide

  416. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println,
    Throwable::printStackTrace,
    () -> System.out.println("Completed !"));

    View full-size slide

  417. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println,
    Throwable::printStackTrace,
    () -> System.out.println("Completed !"));

    View full-size slide

  418. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println,
    Throwable::printStackTrace,
    () -> System.out.println("Completed !"));

    View full-size slide

  419. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println,
    Throwable::printStackTrace,
    () -> System.out.println("Completed !"));

    View full-size slide

  420. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println,
    Throwable::printStackTrace,
    () -> System.out.println("Completed !"));

    View full-size slide

  421. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(tps -> Observable.just(1, 2, 3))
    .subscribe(System.out::println,
    Throwable::printStackTrace,
    () -> System.out.println("Completed !"));
    Cela n’arrivera
    jam
    ais !

    View full-size slide

  422. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Il faut comprendre
    le contrat Rx
    pour comprendre
    les opérateurs

    View full-size slide

  423. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .toList()
    .subscribe(System.out::println);

    View full-size slide

  424. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .toList()
    .subscribe(System.out::println);

    View full-size slide

  425. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .toList()
    .subscribe(System.out::println);

    View full-size slide

  426. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    toList()
    toList()

    View full-size slide

  427. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    toList()
    toList()

    View full-size slide

  428. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval

    View full-size slide

  429. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval
    Fin du flux ?

    View full-size slide

  430. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .toList()
    .subscribe(System.out::println);

    View full-size slide

  431. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Hot versus Cold

    View full-size slide

  432. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Un Cold Observable créé
    l'émetteur

    View full-size slide

  433. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Un Hot Observable
    utilise un émetteur
    existant

    View full-size slide

  434. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    Timer timer = new Timer();
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();

    View full-size slide

  435. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    Timer timer = new Timer();
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();

    View full-size slide

  436. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    Timer timer = new Timer();
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();

    View full-size slide

  437. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    Timer timer = new Timer();
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();
    Cold

    View full-size slide

  438. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Timer timer = new Timer();
    Observable.create(subscriber -> {
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();

    View full-size slide

  439. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Timer timer = new Timer();
    Observable.create(subscriber -> {
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();

    View full-size slide

  440. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Timer timer = new Timer();
    Observable.create(subscriber -> {
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();

    View full-size slide

  441. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Timer timer = new Timer();
    Observable.create(subscriber -> {
    timer.onTick(() -> subscriber.onNext("tick"));
    }).subscribe();
    Hot

    View full-size slide

  442. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();

    View full-size slide

  443. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();
    response
    .map(str -> str.toLowerCase())
    .subscribe(System.out::println);

    View full-size slide

  444. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();
    response
    .map(str -> str.toLowerCase())
    .subscribe(System.out::println);
    response
    .subscribe(System.out::println);

    View full-size slide

  445. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();
    response
    .map(str -> str.toLowerCase())
    .subscribe(System.out::println);
    response
    .subscribe(System.out::println);

    View full-size slide

  446. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();
    response
    .map(str -> str.toLowerCase())
    .subscribe(System.out::println);
    response
    .subscribe(System.out::println);

    View full-size slide

  447. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();
    response
    .map(str -> str.toLowerCase())
    .subscribe(System.out::println);
    response
    .subscribe(System.out::println);
    Cold

    View full-size slide

  448. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();
    response
    .map(str -> str.toLowerCase())
    .subscribe(System.out::println);
    response
    .subscribe(System.out::println);
    Cold
    Création d’un appel
    réseau

    View full-size slide

  449. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable response = ws.call();
    response
    .map(str -> str.toLowerCase())
    .subscribe(System.out::println);
    response
    .subscribe(System.out::println);
    Cold
    Création d’un
    second
    appel réseau
    Création d’un appel
    réseau

    View full-size slide

  450. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Utilisation de MDC pour
    les logs : attention aux
    mauvaises surprises.

    View full-size slide

  451. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    MDC.put("ID", "AAA");
    LOG.warning("first_observable: {}", l);

    View full-size slide

  452. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    WARN AAA [2014-11-10 02:57:24,566] first_observable: 9
    MDC.put("ID", "AAA");
    LOG.warning("first_observable: {}", l);

    View full-size slide

  453. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    WARN AAA [2014-11-10 02:57:24,566] first_observable: 9
    MDC.put("ID", "AAA");
    LOG.warning("first_observable: {}", l);
    Utilisation de ThreadLocal

    View full-size slide

  454. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    WARN AAA [2014-11-10 02:57:24,566] first_observable: 9
    WARN BBB [2014-11-10 02:57:24,576] second_observable: 1
    WARN AAA [2014-11-10 02:57:25,566] first_observable: 10
    WARN CCC [2014-11-10 02:57:25,576] third_observable: 2
    Contexte synchrone

    View full-size slide

  455. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    WARN AAA [2014-11-10 02:57:24,566] first_observable: 9
    WARN BBB [2014-11-10 02:57:24,576] second_observable: 1
    WARN AAA [2014-11-10 02:57:25,566] first_observable: 10
    WARN CCC [2014-11-10 02:57:25,576] third_observable: 2
    Contexte synchrone

    View full-size slide

  456. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    WARN AAA [2014-11-10 02:57:24,566] first_observable: 9
    WARN BBB [2014-11-10 02:57:24,576] third_observable: 1
    WARN AAA [2014-11-10 02:57:25,566] second_observable: 10
    WARN BBB [2014-11-10 02:57:25,576] third_observable: 2
    Contexte asynchrone

    View full-size slide

  457. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    WARN AAA [2014-11-10 02:57:24,566] first_observable: 9
    WARN BBB [2014-11-10 02:57:24,576] third_observable: 1
    WARN AAA [2014-11-10 02:57:25,566] second_observable: 10
    WARN BBB [2014-11-10 02:57:25,576] third_observable: 2
    Contexte asynchrone
    Interleaving

    View full-size slide

  458. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Il est nécessaire de
    remettre en place le
    contexte lors d’un
    changement de
    contexte.

    View full-size slide

  459. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() {
    @Override
    public Action0 onSchedule(Action0 action) {
    return super.onSchedule(() -> {
    MDC.setContextMap(mdcContextMap);
    try {
    action.call();
    } finally {
    MDC.clear();
    }
    });
    }
    });
    http://blog.mabn.pl/2014/11/rxjava-logback-and-mdc-threadlocal.html
    (version courte)

    View full-size slide

  460. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() {
    @Override
    public Action0 onSchedule(Action0 action) {
    return super.onSchedule(() -> {
    MDC.setContextMap(mdcContextMap);
    try {
    action.call();
    } finally {
    MDC.clear();
    }
    });
    }
    });
    http://blog.mabn.pl/2014/11/rxjava-logback-and-mdc-threadlocal.html
    (version courte)
    À chaque planification de tâche

    View full-size slide

  461. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() {
    @Override
    public Action0 onSchedule(Action0 action) {
    return super.onSchedule(() -> {
    MDC.setContextMap(mdcContextMap);
    try {
    action.call();
    } finally {
    MDC.clear();
    }
    });
    }
    });
    http://blog.mabn.pl/2014/11/rxjava-logback-and-mdc-threadlocal.html
    (version courte)
    À chaque planification de tâche
    On planifie une autre tâche

    View full-size slide

  462. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() {
    @Override
    public Action0 onSchedule(Action0 action) {
    return super.onSchedule(() -> {
    MDC.setContextMap(mdcContextMap);
    try {
    action.call();
    } finally {
    MDC.clear();
    }
    });
    }
    });
    http://blog.mabn.pl/2014/11/rxjava-logback-and-mdc-threadlocal.html
    (version courte)
    À chaque planification de tâche
    On planifie une autre tâche
    Qui remet le contexte
    et qui exécute notre tâche

    View full-size slide

  463. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(i -> {
    try {
    RandomException.mayThrowException();
    return Observable.empty();
    } catch (IOException e) {
    return Observable.error(e);
    }
    }).subscribe(System.out::println, e -> { /* ... */ });

    View full-size slide

  464. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(i -> {
    try {
    RandomException.mayThrowException();
    return Observable.empty();
    } catch (IOException e) {
    return Observable.error(e);
    }
    }).subscribe(System.out::println, e -> { /* ... */ });
    Quelle valeur a généré l’exception ?

    View full-size slide

  465. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(i -> {
    try {
    RandomException.mayThrowException();
    return Observable.empty();
    } catch (IOException e) {
    return Observable.error(OnErrorThrowable.addValueAsLastCause(e, i));
    }
    }).subscribe(System.out::println, e -> { /* ... */ });
    Associe l’exception avec une valeur

    View full-size slide

  466. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .flatMap(i -> {
    try {
    RandomException.mayThrowException();
    return Observable.empty();
    } catch (IOException e) {
    return Observable.error(OnErrorThrowable.addValueAsLastCause(e, i));
    }
    }).subscribe(System.out::println, e -> {
    Object value = OnErrorThrowable.from(e).getValue();
    });
    Récupère la valeur depuis l’exception

    View full-size slide

  467. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Grâce à OnErrorThrowable,
    il est possible d'accéder à
    la valeur responsable de
    l’exception

    View full-size slide

  468. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    public interface WebService {
    Observable call();
    }
    Va émettre une valeur ?
    Va émettre plusieurs
    valeurs ?
    Va émettre aucune
    valeur ?

    View full-size slide

  469. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Single = onSuccess | onError
    (Actuellement en @Beta)

    View full-size slide

  470. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Completable = onCompleted | onError
    (Actuellement en @Experimental)

    View full-size slide

  471. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    public interface WebService {
    Observable list();
    Single get();
    Completable perform();
    }
    Va émettre un ensemble de
    valeurs
    va émettre une unique valeur
    ne va pas émettre de valeur

    View full-size slide

  472. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Single et Completable
    permettent d’exprimer
    une intention.

    View full-size slide

  473. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    La souscription permet
    de signaler le
    désabonnement
    à un flux

    View full-size slide

  474. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(System.out::println);

    View full-size slide

  475. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Subscription interval = Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(System.out::println);
    Tada !

    View full-size slide

  476. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Subscription interval = Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(System.out::println);
    interval.unsubscribe();
    Stop le flux

    View full-size slide

  477. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    CompositeSubscription
    permet de
    gérer un ensemble
    d’abonnements

    View full-size slide

  478. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Subscription flux1 = Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(System.out::println);
    Subscription flux2 = Observable.interval(100, TimeUnit.MILLISECONDS)
    .subscribe(System.err::println);

    View full-size slide

  479. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Subscription flux1 = Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(System.out::println);
    Subscription flux2 = Observable.interval(100, TimeUnit.MILLISECONDS)
    .subscribe(System.err::println);
    flux1.unsubscribe();
    flux2.unsubscribe();

    View full-size slide

  480. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Subscription flux1 = Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(System.out::println);
    Subscription flux2 = Observable.interval(100, TimeUnit.MILLISECONDS)
    .subscribe(System.err::println);
    CompositeSubscription subscription = new CompositeSubscription();
    subscription.add(flux1);
    subscription.add(flux2); Compose les abonnements

    View full-size slide

  481. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Subscription flux1 = Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(System.out::println);
    Subscription flux2 = Observable.interval(100, TimeUnit.MILLISECONDS)
    .subscribe(System.err::println);
    CompositeSubscription subscription = new CompositeSubscription();
    subscription.add(flux1);
    subscription.add(flux2);
    subscription.unsubscribe(); Désabonne les flux

    View full-size slide

  482. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    private CompositeSubscription subscription;
    @Override
    public void onResume() {
    Subscription interval = Observable.interval(1, TimeUnit.SECONDS)
    .subscribe(/* ... */);
    Subscription click = clicks()
    .subscribe(/*...*/);
    subscription = new CompositeSubscription();
    subscription.add(interval);
    subscription.add(click);
    }
    @Override
    public void onPause() {
    subscription.unsubscribe();
    }
    Désabonne les flux

    View full-size slide

  483. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Du code peut être
    exécuté lors du
    désabonnement

    View full-size slide

  484. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    subscriber.add(new Subscription() {
    @Override
    public void unsubscribe() {
    // fermeture du flux
    }
    });
    });
    Fermeture des ressources, etc

    View full-size slide

  485. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.create(subscriber -> {
    subscriber.add(new Subscription() {
    @Override
    public void unsubscribe() {
    // fermeture du flux
    }
    });
    });

    View full-size slide

  486. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Mais comment le faire
    sans utiliser
    Observable.create ?

    View full-size slide

  487. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using(
    () -> new DB(),
    db -> Observable.just(db.doQuery()),
    db -> db.closeDb())
    .subscribe();

    View full-size slide

  488. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable.using(
    () -> new DB(),
    db -> Observable.just(db.doQuery()),
    db -> db.closeDb())
    .subscribe();
    Fermeture des ressources, etc

    View full-size slide

  489. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Avant de se dire au revoir

    View full-size slide

  490. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Les autres talks sur les Reactive Extensions
    - A lite Rx API for the JVM
    Hands On Labs - Mercredi 9h30
    - Baptême du feu avec Rx
    Hands On Labs - Vendredi 11h00
    Alexandre Victoor
    Florent Le Gall
    Sebastien Deleuze
    Stephane Maldini

    View full-size slide

  491. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Remerciements
    Gautier Mechling @Nilhcem
    Simon Baslé @simonbasle
    David Karnok @akarnokd
    Dan Lew @danlew42

    View full-size slide

  492. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Retrouvez nous
    dans les couloirs
    de Devoxx

    View full-size slide

  493. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Y a t’il des points que
    nous n’aurions
    pas abordés ?

    View full-size slide

  494. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Merci

    View full-size slide

  495. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View full-size slide

  496. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View full-size slide