title: How to combine/chain multiple Mono/Flux containing different datatypes without nested subscriptions
body: <p>We are using project-reactor to retrieve some data from an external webservice and generate a bunch of resulting objects.</p>
  
  <p>First we need to fetch some masterdata that is needed to trigger the next webservice calls. After the masterdata is available we retrieve some more data based on the results of the masterdata. Next we have to wait for all Monos to emit it's result. Then we process all the data and build our resulting object.</p>
  
  <p>We don't have much experience with reactive-streams. Our solution with the nested subscriptions works but we believe that there might be a better way to archive what we want to do.</p>
  
  <p><strong>Question 1</strong></p>
  
  <p>Masterdata_A and Masterdata_B could be fetched in parallel but how to express this in a reactive way without nesting?
  Each result of getFluxMasterdata_B should be combined with the one result of getMonoMasterdata_A.</p>
  
  <p><strong>Question 2</strong></p>
  
  <p>The Tupel with both Masterdatas should be limited in some way to not overwhelme the webservice with to many data-requests. The actual delay of 1second is just a guess that seems to work but it would be better to define a max number of parallel executions of the first inner flatMap to have a maximum of N waiting webservice calls at a time.</p>
  
  <p><strong>Question 3</strong></p>
  
  <p>In future there might be some more data we must fetch from the webservice to build the ProcessingResult. Is there a best practice to define the reactive-stream to keep it readable/understandable?
  Is nesting of reactive-streams OK or should it be avoided (keep everything on the top level)?</p>
  
  <hr>
  
  <p><strong>DomainModel</strong></p>
  
  <pre><code>    private static class Masterdata_A
      {
          private List&lt;MasterdataRecord_A&gt; records;
      }
  
      private static class MasterdataRecord_A { /* ... business relevant fields */ }
      private static class MasterdataRecord_B { /* ... business relevant fields */ }
      private static class Data_A { /* ... business relevant fields */ }
      private static class Data_B { /* ... business relevant fields */ }
      private static class Data_C { /* ... business relevant fields */ }
  
      private static class ProcessingResult { /* ... business relevant fields */ }
  </code></pre>
  
  <p><strong>WebserviceImpl</strong></p>
  
  <pre><code>    private static class Webservice
      {
          private Mono&lt;Masterdata_A&gt; getMonoMasterdata_A() { /* fetch data from external webservice */ }
          private Flux&lt;MasterdataRecord_B&gt; getFluxMasterdata_B() { /* fetch data from external webservice */ }
  
          private Mono&lt;Data_A&gt; getMonoData_A() { /* fetch data from external webservice */ }
          private Mono&lt;Data_B&gt; getMonoData_B() { /* fetch data from external webservice */ }
          private Mono&lt;Data_C&gt; getMonoData_C() { /* fetch data from external webservice */ }
      }
  </code></pre>
  
  <p><strong>BusinessServiceImpl</strong></p>
  
  <pre><code>    public class BusinessService
      {
          public void processData(...params...)
          {
              Webservice webservie = getWebservice();
              // As soon as Mono&lt;Masterdata_A&gt; emits its result AND Flux&lt;Masterdata_B&gt; emits its first result than the first inner flatMap should be executed
              // to fetch some extra data from the service based on the actual masterdata.
              // For building the ProcessingResult we need access to all data available in the actual context.
              webservice.getMonoMasterdata_A()
                      .subscribe((Masterdata_A masterdataA) -&gt; {
                          webservice.getFluxMasterdata_B()
                                  .delayElements(Duration.ofSeconds(1))
                                  .flatMap((MasterdataRecord_B masterdataB) -&gt; {
                                      Mono&lt;Data_A&gt; monoA = webservice.getMonoData_A(masterdataA);
                                      Mono&lt;Data_B&gt; monoB = webservice.getMonoData_B(masterdataB);
                                      Mono&lt;Data_C&gt; monoC = webservice.getMonoData_C(masterdataA, masterdataB);
                                      // wait for result of all Monos
                                      return Mono.zip(monoA, monoB, monoC);
                                  })
                                  .flatMap((Tuple3&lt;Data_A, Data_B, Data_C&gt; data) -&gt; {
                                      Data_A dataA = data.getT1();
                                      Data_B dataB = data.getT2();
                                      Data_C dataC = data.getT3();
  
                                      // create result from masterdataA, masterdataB, dataA, dataB, dataC
                                      ProcessingResult result = ...;
                                      return Mono.just(result);
                                  })
                                  .subscribe(processingResult -&gt; {
                                      // store result to db/filesystem
                                  });
                      });
          }
      }
  </code></pre>