4

I am currently migrating our existing Spring asynchronous REST architecture to Spring's new WebFlux library and have a question around joining multiple requests so that they can listen for the same published response.

Use Case is as follows:

  1. Client A connects to our web server and requests data
  2. We hit our cache to check if we have the data there
  3. We don't, so we go and retrieve this data (Client A has subscribed and waits for a response)
  4. Client B connects to our web server and requests the same data (hits the same endpoint)
  5. We check the cache, data is still not there
  6. As we are already fetching this data for Client A we don't want to make another request, however, we also do not want to turn Client B away. Client B should be able to listen for the same information

How can Client B subscribe to the same response stream that Client A is waiting for?

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
wild_nothing
  • 2,845
  • 1
  • 35
  • 47
  • Could you give code snippets to show how the caching library API looks like? Also, what is the expected behavior here? I assume that the cache may not contain the raw response to be sent to the client so it's about sharing the cached data at the service layer, not necessarily at the web layer? – Brian Clozel Apr 13 '18 at 17:18
  • I'm actually just wondering if it's possible with reactive patterns. The cache is used in the example to show why a request might not get a response immediately. I'm wondering if two requests hit the same endpoint, is it possible with WebFlux to join them and allow them to both wait on the same response? Obviously this can't be done with classic REST and Spring, but I was hoping this sort of behaviour was possible with reactive streams. – wild_nothing Apr 14 '18 at 10:42

1 Answers1

8

"Client A has subscribed and waits for a response" I suppose the request is coded as a Mono and client A sibscribes to it literally:

Subscriber<Response> clientA = ... Mono<Response> request = makeRequest(...); request.subscribe(clientA);

then clientB should subscribe the same way:

Subscriber<Response> clientB = ... request.subscribe(clientB);

Moreover, the cache should contain not the previously saved response data, but the requests themselves, of type Mono<Response>. Then, if such a request is found in the cache, new clients simply subscribe to it, regardless of was that request already completed or not.

Alexei Kaigorodov
  • 13,189
  • 1
  • 21
  • 38
  • 1
    The "cache" in this example is simply a very light Hazelcast IMap data structure. It is populated with data from an external source if and only if said data is not already there. What I'm trying to do is enforce the external data call (and cache population) doesn't happen twice in the most elegant manner. There are a multitude of ways to already solve this problem but I'd like to know if I can solve it in a simple manner with WebFlux - my idea being two requests listen to the same sequence of events. I can't remove my existing IMap, but you think I should add a new one containing Mono? – wild_nothing Apr 15 '18 at 21:09
  • Just like processors has several levels of cache, you can add another level of cache for current requests, containing Mono, without touching IMap. This can be simple HashMap. – Alexei Kaigorodov Apr 15 '18 at 22:25
  • Interesting, idea. Thanks. – wild_nothing Apr 16 '18 at 07:41
  • 1
    You can simply move received response from the cache for Mono to main cache: `request.subscribe(response)->{ imapCache.put(response); responseCache.remove(request); }` – Alexei Kaigorodov Apr 17 '18 at 11:48