title: Spring webflux - AOP How to use aspect such that it is processed before the call to blocking operation( pushed onto a background thread)
body: <p>I have  Restful application written on spring webflux.</p>
  <p>In my use case, I have to call a blocking operation that will do some processing. The blocking call is being run in a separate thread pool. ( done by calling the blocking operation inside a callable)<br />
  I have added aspect on the method <code>myServiceMethod</code> in which a <code>Flatmap</code> does some transformation on it.
  Now the purpose of adding aspect here was to capture the total time taken by the rest api ( excluding the time taken by  <code>blockMethod</code>).
  But the implementation is somehow being processed in a way that it only logs the data after processing the blocking code.
  What can be fixed here so as to make sure aspect processes before the <code>blockMethod</code> is called.</p>
  <pre class="lang-java prettyprint-override"><code>private Mono&lt;Result&gt; myServiceMethod(String any1, String any2) {
    return myWebClient.get()
      .uri(&quot;http://I-just-wsnt-log-the-round-trip-time-fro-api-call.com/&quot;).bodyToMono(Result)
      .flatMap(someThing -&gt; myCallable(someThing));
  }
  
  private Mono&lt;Result&gt; myCallable(int value) {
    return Mono.fromCallable(() -&gt; blockMethod(value))
      .subscribeOn(this.scheduler);
  }
  </code></pre>
  <p>*Note : The above code could be a bit faulty, but hope it okay as long as it conveys the idea.
  And My aspect code using pointcut is as follows :</p>
  <pre class="lang-java prettyprint-override"><code>@Pointcut(&quot;execution(public * MyClass.myServiceMethod(..))&quot;)
  public void custompoint() {}
  
  @Around(&quot;custompoint()&quot;)
  public Mono&lt;String&gt; calculateTimeAdStuff(ProceedingJoinPoint joinPoint) {
    return Mono.just(1)
      .flatMap(logTime(joinPoint));
  }
  
  // logging time taken by calling ProceedingJoinPoint.proceed
  private Mono&lt;String&gt; logTime(ProceedingJoinPoint joinPoint) {
    Instant start = Instant.now();
    return ((Mono&lt;Result&gt;)joinPoint.proceed()).flatMap(() -&gt; {
      String log = Instant.now().toMillis() - start);
      return Mono.just(log);
    });
  }
  </code></pre>
  <p>My question is how can I change this by making sure that the logged time is not including the time take by <code>blockMethod</code>.</p>
  <h2>Update</h2>
  <p>I have tried some things with context. Adding my changes here. But seems that my changes made in the context are not reaching the advice where I call <code>jointpoint.proceed</code>.</p>
  <pre class="lang-java prettyprint-override"><code>private Mono&lt;Result&gt; myServiceMethod(String any1, String any2) {
    return myWebClient.get()
      .uri(&quot;http://I-just-want-log-the-round-trip-time-for-api-call.com/&quot;).bodyToMono(Result)
      .flatMap(someThing -&gt; myCallable(someThing))
      .subscriberContext(ctx -&gt; ctx.put(&quot;timeTakenTest&quot;, 56000L ));
  }
  
  </code></pre>
  <p>Here is the code of the advice method. Here the value of key<code>&quot;timeTakenTest&quot;</code> is always 0 (default) when printed. so clearly the entry I added in the subscriberContext in the executed method is not available here.</p>
  <p>The <code>.replacing </code>getOrDefault<code>with</code>get` gives error as below. so clearly its either never being added to context or in the middle somewhere context is getting recreated causing this issue.</p>
  <pre class="lang-java prettyprint-override"><code>java.util.NoSuchElementException: Context does not contain key: timeTakenTest
  </code></pre>
  <pre class="lang-java prettyprint-override"><code>// logging time taken by calling ProceedingJoinPoint.proceed
  private Mono&lt;String&gt; logTime(ProceedingJoinPoint joinPoint) {
    Instant start = Instant.now();
    return ((Mono&lt;Result&gt;)joinPoint.proceed())
    .zipWith(Mono.subscriberContext() 
                  .map(c -&gt; (Long)c.getOrDefault(&quot;timeTakenTest&quot;, 0L))).flatMap(responseData -&gt; {
               System.out.println(&quot;Subscription time registered is : &quot; + responseData.getT2());
       //something done here.
    });
  }
  </code></pre>
  <p>I think I have followed the documentation good.
  It even says in the document :</p>
  <blockquote>
  <p>subscriberContext(Context) merges the Context you provide and the Context from downstream (remember, the Context is propagated from the bottom of the chain towards the top). This is done through a call to putAll, resulting in a new Context for upstream.</p>
  </blockquote>
  <p>Please suggest.</p>
  <p>Reference : <a href="https://projectreactor.io/docs/core/release/reference/#context.read" rel="nofollow noreferrer">https://projectreactor.io/docs/core/release/reference/#context.read</a></p>