2

Given that i have this service-A with this endpoint which returns contentType(MediaType.TEXT_EVENT_STREAM)

@Bean
    public RouterFunction<ServerResponse> notificationsRoute(CustomHandler someCustomHandler) {
        return route()
                .GET("/orders", someCustomHandler:handle)
                .build();
    }

I need to consume that from another spring boot service-B, which currently uses restTemplate (its not reactive yet).

  1. Question 1-> can this be done using restTemplate, and somehow SseEmitter (to stream to UI) class to stream the events from service-A.
  2. Question 2 -> Given that this service-B is a normal MVC, with spring security integration. can i also bring webflux and have both working ?
  3. Question 3 -> is there any other potential solutions for that scenario.

Even if i bring spring webflux i was gettting some security filter chain duplicate beans.

2
  • You can have both MVC and Webflux on the classpath. However, You might have to explicitly define spring.main.web-application-type: servlet in your properties, otherwise Spring might have trouble to understand if it must start an MVC or Webflux server. But adding webflux should allow you to use the reactive WebClient. Otherwise, I do not know if it is achievable with RestTemplate. Maybe the new non-reactive RestClient has streaming capabilities, but I've not tested it yet. Commented May 2, 2024 at 13:04
  • thanks @amanin for your response. But if I do this "spring.main.web-application-type: servlet" then when i call that endpoint which is describe as a Route, i get 404, which means then spring boot is not exposing that endpoint which is not what i want.. I will take a look a RestClient to see if the latest implementation allows some sort of Server side events. Commented May 4, 2024 at 18:27

1 Answer 1

1

Question 1-> can this be done using restTemplate, and somehow SseEmitter (to stream to UI) class to stream the events from service-A.

Question 1: Yes, it's possible to consume an SSE (Server-Sent Events) stream from service-A using RestTemplate, but it's not the most efficient approach. RestTemplate is synchronous and blocking, while SSE is an asynchronous and non-blocking protocol. However, you can still use RestTemplate with a workaround to handle SSE. You would need to create a separate thread to continuously read from the SSE stream and process the events. SseEmitter is not directly compatible with RestTemplate, as it's a part of Spring WebFlux, which is designed for reactive programming.

Given that this service-B is a normal MVC, with spring security integration. can i also bring webflux and have both working ?

Question 2: Yes, you can bring in Spring WebFlux alongside Spring MVC with Spring Security integration. Spring WebFlux is designed to work seamlessly with Spring MVC, allowing you to gradually migrate towards a reactive architecture. You can have both working together in the same application.

is there any other potential solutions for that scenario.

Question 3: Potential solutions for your scenario include:

a. Use WebClient (Reactive Approach): Instead of RestTemplate, you can use WebClient from Spring WebFlux, which is non-blocking and reactive. It's better suited for consuming reactive streams like SSE.

b.Proxy Service: Create a separate Spring WebFlux service that consumes the SSE stream from service-A and exposes a REST API. Then, your Spring MVC service-B can consume this REST API using RestTemplate.

NON-BLOCKING - Reactive -SSE



@RestController
public class SSEController {

    @GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> streamEvents() {
        return Flux.interval(Duration.ofSeconds(1))
                .map(sequence -> ServerSentEvent.<String>builder()
                        .id(String.valueOf(sequence))
                        .event("event")
                        .data("SSE Event #" + sequence + " at " + LocalTime.now())
                        .build());
    }
}

DEPENDENCY

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

SERLVET BLOCKING-MODEL SSE


@RestController
public class SSEController {

    @GetMapping("/events")
    public SseEmitter streamEvents() {
        SseEmitter emitter = new SseEmitter();
        
        // Using a scheduled executor service to simulate periodic events
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleAtFixedRate(() -> {
            try {
                // Send event data
                emitter.send(SseEmitter.event().data("SSE Event at " + LocalTime.now()));
            } catch (IOException e) {
                // Log or handle the exception
            }
        }, 0, 1, TimeUnit.SECONDS);

        // Complete the emitter after a fixed delay
        executorService.schedule(() -> {
            emitter.complete();
            executorService.shutdown();
        }, 10, TimeUnit.SECONDS);

        return emitter;
    }
}

Besides spring.main.web-application-type: servlet , you can code like following to start up different web service container .

 SpringApplication app = new SpringApplication(Application.class);
        app.setWebApplicationType(WebApplicationType.SERVLET);
        app.run(args);
public enum WebApplicationType {
    NONE,
    SERVLET,
    REACTIVE;
}
Sign up to request clarification or add additional context in comments.

1 Comment

thanks @Peng I decided to use a proxy service using webclient to stream events to the clients, little bit more work up front but worth it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.