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).
Even if i bring spring webflux i was gettting some security filter chain duplicate beans.
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.
@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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
@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;
}