IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Plateformes réactives et architectures modulaires Java Discussion :

[Reactor]Combiner des mono et Flux avec


Sujet :

Plateformes réactives et architectures modulaires Java

  1. #1
    Membre habitué Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    juillet 2004
    Messages
    579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : juillet 2004
    Messages : 579
    Points : 185
    Points
    185
    Par défaut [Reactor]Combiner des mono et Flux avec
    Bonjour,
    je débute avec la programmation réactive et je suis confronté à un problème de compréhension....
    Je ne sais pas quelle méthode utiliser pour combiner le résultat de plusieurs microservice dans un seul et même objet
    Pour consommer les différents microservices, j'utilise WebClient.
    Le premier résultat se fait de façon bloquante car c'est "l'objet principal" qui me permet d'aller récupérer ensuite les informations dans les autres microservices
    Les autres appels peuvent se faire de façon asynchrone
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
        @GetMapping("/operation-detail/{id}")
        public Mono<OperationDetailDto> getListOfOperations(@PathVariable(name = "id") String operationId){
            OperationFullDto operation =
                    webClient.build()
                            .get().uri("lb://operation-query-microservice/operation/" + operationId)
                            .retrieve()
                            .bodyToMono(OperationFullDto.class)
                            .block();
            Flux<OuvrageDto> ouvrages =
                    webClient.build()
                    .get().uri("lb://ouvrage-microservice/ouvrage/"+operation.getOuvrages())
                    .retrieve()
                    .bodyToFlux(OuvrageDto.class);
            Flux<PersonneDto> chefEus =
                    webClient.build()
                            .get().uri("lb://personne-microservice/personne/"+operation.getChefEus())
                            .retrieve()
                            .bodyToFlux(PersonneDto.class);
            Flux<PersonneDto> donneurOrdre =
                    webClient.build()
                            .get().uri("lb://personne-microservice/personne/"+operation.getChefEus())
                            .retrieve()
                            .bodyToFlux(PersonneDto.class);
     
     
            Mono<OperationDetailDto> operationDetail =
            //ToDo
     
            return operationDetail;
     
        }
    OperationFullDto
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class OperationFullDto {
     
        private UUID id;
        private String titre;
        private List<Long> ouvrages;
        private List<Long> chefEus;
        private List<Long> donneurOrdres;
    ...
     
    }
    OuvrageDto
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public class OuvrageDto {
     
        private Long id;
        private TypeDto type;
        private String organisation;
    ...
    }
    PersonneDto
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class PersonneDto {
     
        private Long id;
        private String name;
        private String surname;
        private String email;
        private List<Role> roles;
     
    }
    OperationDetailDto
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public class OperationDetailDto {
        private UUID id;
        private String titre;
        private List<OuvrageDto> ouvrages;
        private List<PersonneDto> chefEus;
        private List<PersonneDto> donneurOrdres;
    ...
    }
    Savez-vous quelle méthode est plus appropriée pour faire mon appel bloquant puis les x appels asynchrone ?
    Comment puis combiner le résultat dans un seul est même objet (OperationDétailDto) ?

    merci pour vos éclaircissements

  2. #2
    Membre habitué Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    juillet 2004
    Messages
    579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : juillet 2004
    Messages : 579
    Points : 185
    Points
    185
    Par défaut
    Bonjour,

    j'ai un peu avancé sur le sujet mais je suis toujours bloqué...

    J'ai créé des services pour récupérer les données avec WebClient

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    @Service
    public class OperationClient {
     
        private final WebClient webClient;
     
        public OperationClient(WebClient.Builder builder) {
            this.webClient = builder.baseUrl("lb://operation-query-microservice/operation/").build();
        }
     
        public Mono<OperationFullDto> getOperation(String operationId){
            return webClient
                    .get()
                    .uri("{id}" , operationId)
                    .retrieve()
                    .bodyToMono(OperationFullDto.class)
                    .onErrorResume(ex->Mono.empty());
     
        }
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    @Service
    public class OuvrageClient {
     
        private final WebClient webClient;
     
        public OuvrageClient(WebClient.Builder builder) {
            this.webClient = builder.baseUrl("lb://ouvrage-microservice/ouvrage/").build();
        }
     
        public Mono<List<OuvrageDto>> getOuvrages(List<Long> ids){
            return webClient
                    .get()
                    .uri("{ids}",ids)
                    .retrieve()
                    .bodyToFlux(OuvrageDto.class)
                    .collectList()
                    .onErrorReturn(Collections.emptyList());
        }
     
    }
    le service suivant permet de combiner le résultat des deux autres services :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    @Service
    @AllArgsConstructor
    public class CombinedOperationService {
     
        private final OperationClient operationClient;
        private final OuvrageClient ouvrageClient;
     
        public Mono<OperationDetailDto> getDetails(String operationId){
     
            Mono<OperationFullDto> operationMono = operationClient.getOperation(operationId);
     
            // uniquement pour le test.... le temps de trouver comment récupérer
            // la liste des ouvrages dans le operationMono avant de lancer la méthode getOuvrage
            List<Long> listDeTest = new ArrayList<>();
            listDeTest.add(1L);
            listDeTest.add(2L);
     
            Mono<List<OuvrageDto>> ouvragesMono = ouvrageClient.getOuvrages(listDeTest);
     
            return Mono.zip(
                    operationMono,
                    ouvragesMono
            )
            .map(this::combine);
        }
     
        private OperationDetailDto combine (Tuple2<OperationFullDto, List<OuvrageDto>> tuple){
            return OperationDetailDto.create(
                    tuple.getT1(),
                    tuple.getT2()
            );
        }
     
    }
    1) Comment puis-je attendre le résultat du premier service (OperationClient) afin de récupérer la List des ouvrages et l'injecter dans les paramètre du second service (OuvrageClient) ?
    j'ai essayé de faire un .block() mais j'ai un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3
    2) Puis-je utiliser la méthode zip pour combiner un Mono() et un Flux() ? Actuellement mon service (OuvrageClient) retourne un Mono.... Mon publisher (lb//ouvrage-microservice/ouvrage/) remonte un Flux d'ouvrage

    D'avance merci pour votre aide

  3. #3
    Membre averti
    Homme Profil pro
    Architecte technique
    Inscrit en
    mai 2020
    Messages
    246
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : mai 2020
    Messages : 246
    Points : 319
    Points
    319
    Par défaut
    Bonjour,

    Je n'ai jamais utilisé Ractor directement mais j'ai l'impression que flatMap pourrait vous aider:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
      private Mono<List<Ouvrage>> getOuvrages(String operationId) {
        // ...
      }
     
     webClient.build()
       .get().uri("lb://operation-query-microservice/operation/" + operationId)
       .retrieve()
       .bodyToMono(OperationFullDto.class)
       .flatMap(op -> {
         OperationDetailDto detail = new OperationDetailDto(op);
         getOuvrages(detail.id).map(ouvrages -> {
           detail.setOuvrages(ouvrages);
           retrun detail;
         })
       })
      .flatMap(detail -> {
         getDonnerOrdre(detail.id).map(personne -> {
           detail.setDonnerOrder(personne);
           retrun detail;
         })
       })

  4. #4
    Membre habitué Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    juillet 2004
    Messages
    579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : juillet 2004
    Messages : 579
    Points : 185
    Points
    185
    Par défaut
    Bonjour,
    un grand merci pour votre réponse.
    Je vais regarder ça et vous faire un retour !

    Cordialement

  5. #5
    Membre habitué Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    juillet 2004
    Messages
    579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : juillet 2004
    Messages : 579
    Points : 185
    Points
    185
    Par défaut
    Ca avance.. ça avance

    J'arrive bien à récupérer mon Mono OperationFullDto et j'arrive à récupérer mes Mono d'ouvrages via mes webClients.....
    Par contre, ma liste d'ouvrageDto est vide

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
        public Mono<OperationDetailDto2> getDetails(String operationId){
            return operationClient.getOperation(operationId)
                    .flatMap(op -> {
                        OperationDetailDto2 detail = new OperationDetailDto2(op);
                        op.getOuvrages().forEach(ouvrageId ->
                                ouvrageClient.getOuvrage(ouvrageId).map(ouvrage -> {
                                    List<OuvrageDto> ouvrageDtos = detail.getOuvrageDtos();
                                    System.out.println(ouvrage.getAdr());
                                    ouvrageDtos.add(ouvrage);
                                    detail.setOuvrageDtos(ouvrageDtos);
                                    return detail;
                                }).subscribe()
                        );
                        return Mono.just(detail);
                    })
     
                    /*.flatMap(detail -> {
                        getDonnerOrdre(detail.id).map(personne -> {
                            detail.setDonnerOrder(personne);
                            return detail;
                        })
                    })*/
                    ;
        }

  6. #6
    Membre averti
    Homme Profil pro
    Architecte technique
    Inscrit en
    mai 2020
    Messages
    246
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : mai 2020
    Messages : 246
    Points : 319
    Points
    319
    Par défaut
    Bonjour,

    Est-ce que ça ne serait pas à cause du parallélisme que vos ouvrages sont vides ?

    Il me semble que op.getOuvrages().forEach va s'executer lorsque vous allez recevoir les ouvrages. Mais ce code n'est pas bloquant, donc vous retournez peut-être le details avant que les ouvrages ne soient assignés. D'ou l'utilisation de map ou flatMap qui va "attendre le résultat pour retourner".

  7. #7
    Membre habitué Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    juillet 2004
    Messages
    579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : juillet 2004
    Messages : 579
    Points : 185
    Points
    185
    Par défaut
    Bonsoir,
    Probablement … mais j’avoue être un peu perdu dans la programmation réactive.
    Pour moi je peux retourner un objet incomplet .. et celui-ci se complète au fur et mesure … les traces dans la console montrent bien que j’arrive à récupérer les ouvrages … 🤔

  8. #8
    Membre averti
    Homme Profil pro
    Architecte technique
    Inscrit en
    mai 2020
    Messages
    246
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : mai 2020
    Messages : 246
    Points : 319
    Points
    319
    Par défaut
    mais j’avoue être un peu perdu dans la programmation réactive.
    Dans ce cas il faudrait commencer par vous y retrouver sinon vous allez détester ça ;-)


    et celui-ci se complète au fur et mesure
    En effet, il se complète au fur et à mesure. Mais si vous affichez l'objet avant qu'il ne soit complété il restera vide..


    En programmation concurrentielle, on préfère les objets immuables car ça évite les effets de bords. Idéalemment, une "fonction" ne va pas modifier un objet mais elle va retourner une nouvelle instance de cet objet avec les modifications attendues. Il n'y à donc pas d'effets de bords qui pourraient changer l'état de votre objet à un certain moment. Vous raisonnez alors avec une série de "fonctions" qui sont chainées, appelées les unes après les autres:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     getOperation() 
       andThen 
          (operation -> getOuvrages(operation))
    Il n'y à pas de andThen dans Reactor mais flatMap y ressemble assez bien.

  9. #9
    Membre habitué Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    juillet 2004
    Messages
    579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : juillet 2004
    Messages : 579
    Points : 185
    Points
    185
    Par défaut
    Dans ce cas il faudrait commencer par vous y retrouver sinon vous allez détester ça ;-)
    je crois que je ne suis pas loin de détester ça depuis le temps que je passe dessus ...

    Je pense repartir sur de la programmation impérative... Au moins je vais pouvoir sortir quelque chose que je comprend

    Merci beaucoup pour ton aide

Discussions similaires

  1. Combiner des tableaux Power Query avec une boucle FOR
    Par mm12345 dans le forum Macros et VBA Excel
    Réponses: 14
    Dernier message: 13/04/2022, 15h14
  2. Réponses: 17
    Dernier message: 08/04/2020, 21h24
  3. Réponses: 2
    Dernier message: 12/02/2009, 19h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo