How to delay emitting each item in iterable Spring Boot Flux

Viewed 578

My problem is slightly different, but I can describe the issue in the following manner.

What I would like is some code that emits an item every delay period (3 seconds). But when I hit the /flux URL, the page waits for 3 seconds and gives all 4 items. That means it emits all the items after 3 seconds instead of one item every 3 seconds.

@RestController
@RequestMapping("/flux")
public class MyController {

    List<Item> items = Arrays.asList(
            new Item("name1","description1"),
            new Item("name2","description2"),
            new Item("name3","description3"),
            new Item("name4","description4"));
    @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    Flux<Item> getItems(){
        return Flux.fromIterable(items)
                .delayElements(Duration.ofSeconds(3));
    }
}
@Data
@AllArgsConstructor
class Item{
    String name;
    String description;
}

Update

I saw this post to explain how to do this in RxJava, so I tried this. But with ZipWith the results are worse. Now the page waits 12 seconds. That means the browser response is sent only when Flux is completed... Not Sure why.

Flux<Item> getItems(){
            return Flux.fromIterable(items)
           .zipWith(Flux.interval(Duration.ofSeconds(3)),(item,time)->item);
}

p.s. Using Spring WebFlux dependency, so local started up with Netty not Tomcat.

2 Answers

We can tell the reactor to emit an element after a specific delay by using delayElements(Duration delay). It always tries to emit elements after a specific duration without blocking.

Put this URL in a google chrome browser or any other consumer client like curl instead of the postman.


Curl

curl --location --request GET 'http://localhost:8080/fluxv2' \
--header 'Content-Type: text/event-stream' \
--data-raw ''

Do not try to test the API with postman, because postman doesn't support streaming API's at the moment.


@RestController
@RequestMapping("/fluxv2")
public class MyController {
    Flux<String> stringFlux = Flux.fromIterable(List.of("CM", "Abdullah", "Khan"));
    @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    Flux<String> getItems() {
        return stringFlux.delayElements(Duration.ofSeconds(3)).log();
    }
}

Logs shown that elements are emitting after specific delay

Problem is not in the code, problem is in the browser. If we use Chrome, Both the code mentioned above works as expected. But does not work with safari browser

Related