$30 off During Our Annual Pro Sale. View Details »

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

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

Note cette présentation est la même que https://speakerdeck.com/dwursteisen/architecture-decouplee-grace-aux-reactive-extensions

Vidéo : https://youtu.be/4To7s3qln2s

Brice Dutheil

April 25, 2016
Tweet

More Decks by Brice Dutheil

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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  69. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    Changement
    du code

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  88. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique

    View Slide

  89. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique

    View Slide

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

    View Slide

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

    View Slide

  92. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Historique

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  125. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observer

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 Slide

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

    View Slide

  137. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Observable

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View 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 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 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 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 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 Slide

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

    View Slide

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

    View 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 Slide

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

    View 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View 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 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 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 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 Slide

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

    View 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 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 Slide

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

    View Slide

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

    View 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

  226. #DevoxxFR #Rx
    Reactive Extensions
    En pratique

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View 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 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 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 Slide

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

    View Slide

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

    View 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 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 Slide

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

    View 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 Slide

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

    View 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 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 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View 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 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 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 Slide

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

    View 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 Slide

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

    View 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 Slide

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

    View 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 Slide

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

    View 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 Slide

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

    View 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 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 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 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 Slide

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

    View 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 Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 Slide

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

    View Slide

  361. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View Slide

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

    View Slide

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

    View Slide

  364. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  375. #DevoxxFR #Rx
    Reactive Extensions
    Sur notre application

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 Slide

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

    View 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 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 Slide

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

    View 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 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 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 Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 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 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 Slide

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

    View 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 Slide

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

    View Slide

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

    View 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 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 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 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 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 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 Slide

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

    View 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 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 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 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

  494. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx
    Merci

    View Slide

  495. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View Slide

  496. @BriceDutheil @dwursteisen
    #DevoxxFR #Rx

    View Slide