Spring boot SSE (Server sent events): how to send response dynamically - spring-boot

I am new to SSE (Server Sent Events) . I found a way to send response using SSE in spring boot. I am able to send response for every 20 seconds. I used below code for the same.
public Flux<UserDto> fetchUserEvent() {
return Flux.interval(Duration.ofSeconds(20)).map(intr -> generateUserEvent()).flatMapIterable(x -> x);
}
generateUserEvent() - verify if new user added in DB. If it found user data, will return the same or will return empty object (new UserDto())
But the problem is , this method being called for every 20 seconds .
But , My requirement is to send the empty response to client every 20 seconds and send the respone whenever new user added to DB.
How can I achieve my goal? Or I am totally wrong conceptually.

You should create an event publisher and listener so you can send an event to the emitter when a new user is registered.
Since you're using spring-boot and probably hibernate you can see example here on how to intercept hibernate events.
Hibernate interceptor or listener with Spring Boot and Spring Data JPA
I would personally not use flux and make a scheduled method in spring to send those empty ping responses to the emitter. example of this can be found here: https://www.roytuts.com/server-sent-events-spring-push-notifications/
More info for spring events in general can be found here:
https://www.baeldung.com/spring-events

Related

How to get number of subscribers in spring boot for redis

I am new to redis and i am using spring data redis for implementing some task queue feautre. Since i wanna do some failover checking, is there any a way to get the number of subscriber like in command "pubsub numsub " for a specific channel. Many thanks
if you use spring reactive-Redis with spring boot you can create a specific topic and get the all subscribers that received the published event as a return by publishing a vent ny using convertAndSend method of ReactiveRedisTemplate. but the spring doesn't provide that in imperative way. the convertAndSend method of RedisTemplate doesn't return anything. the return type is void.
stringStringReactiveRedisTemplate
.convertAndSend(
"your topic",
"event message"
).subscribe(receivedCount -> {
System.out.println("num of subscribers the event received: " + receivedCount);
});
you can another way by using the redis connection. it doesn't matter if you use with spring boot. you can get the connection from the redisTemplate and call the publish method to publish the event like below. then you have to provide your channel name and the message by byte[].
Long receivedCount = redisTemplate.getConnectionFactory().getConnection().publish(
"your channel".getBytes(),
"message".getBytes()
);
now you will receive how many live subscribers that event received. (only for that mentioned topic name).
read more https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis:pubsub:publish

Custom spring websocket security with rabbitmq

I'm working with websocket to push notification using rabbitmq like a message broker. In controller i using SimpMessageTemplate to convertAndSendToUser a message via the nick name of user
#PostMapping("/{nickName}/notification")
public void send(#PathVariable String nickName,
#RequestBody NotificationRes notificationRes) {
messagingTemplate.convertAndSendToUser(nickName, "/exchange/amq.direct/notification", notificationRes);
}
I make some configuration by using JWT to authorize user and set user to StompHeaderAccessor when user start connecting.
Spring security messaging currently convert send to user. With that endpoint spring will convert it to /exchange/amq.direct/notification-user{session_id}. And rabbitmq will create an auto deleted queue. So, if I have 100 connect in the same time. It will create 100 queue. I want to custom this flow to create one queue and spring will using message header for spring can know the user to send message to.
I did some research about UserDestinationResolver but I still don't know how to make spring can handle with header instead of url like ...-user{session_id}. #.#. What should i do for this situatioin?

Is it possible for my Spring EventListener to wait for 2 events to progress?

I have a SpringBoot application and have to connect to a websocket server to receive messages, which my application then processes internally using an inbuilt FinitStateMachine (FSM).
What I want is to start the connect() call to the websocket server only after:
my spring application has initialized
my FSM builder has completed the build() call
I have used Spring's ApplicationEventPublisher to publish a custom event (FSMInitializedEvent) when my FSM is built. And the code which initiates connection to websocket server waits for this custom event, but I want my websocket connector code to ALSO wait for Spring's ApplicationReadyEvent. Is there a neat way to do this?
From my FSM's build():
applicationEventPublisher.publishEvent( new FSMInitializedEvent() );
Within my WebSocket connector class:
#EventListener(FSMInitializedEvent.class) <-- HERE i want to listen for this other event too before progressing - ApplicationReadyEvent.class
public void init() {
// code to initiate the connection
}
I could programmatically handle this but looking for some ready to use elegant solution. Also, my question is different what's been suggested here: Use #EventListener annotation on multiple events in Spring, as I want my listener to wait for multiple events to have happened as a precondition, before proceeding.

Spring Cloud Stream - Output Messages from EventListener

I'm trying to utilize the #DomainEvents mechanism provided by Spring Data to publish Events with Spring Cloud Stream (Spring Boot 2.0.0.M7 and Finchley.M5). I have a two-part question.
Why does SendTo not work on EventListeners?
Is there a better way to accomplish this?
The DomainEvent is being created and sent to the EventListener without issues. The problem is that the SendTo mechanism didn't seem to be working. The first method below would trigger, but not forward the message. Manually building the Message and sending it as shown in the second method works correctly.
#Async
#TransactionalEventListener
#SendTo(Sink.Output)
StreamedEvent handleEventWithSendTo(MyEvent event) {
// handle and create event
}
#TransactionalEventListener
void handleEvent(MyEvent event) {
// handle and create event
sink.output().send(MessageBuilder.withPayload(payload).build())
}
The call-out in the Spring Cloud Stream docs shows using SendTo on a StreamListener, which is not quite the same thing as an EventListener, but I thought it may work.
For the second part, using DomainEvents requires the service code persisting the Entity to know about the event (to either call registerEvent directly or some method on the Entity which represents the event). I was curious if using the Spring Data callback hooks (e.g. PreUpdate, PostUpdate) would be better. Or if there was a better way all together.

spring deferredresult

I am new to spring and want to implement long polling for a website to display admin message immediately when it becomes available to all clients,i searched google for hours and could only find out deferredresult(spring 3.2) can be used to implement it.my question is how i can achieve long polling with deferredresult, I would appreciate it if anyone could refer me to such a tutorial.
Another option is to use AsyncContext. This will keep the initial GET request "open" and enable you to send multiple messages as part of the response, unlike DeferredResult which allows to send only ONE response message. Here is a good-link that explains how !
Straight from the horses mouth.
You have two basic options: Option 1 is a Callable
, where the Callable returns the String view name (you may also be able to use #ResponseBody or some of the other normal Spring return types like ModelAndView, but I have never investigated that).
Option two is to return DeferredResult, which is like Callable. except you can pass that off to a separate thread and fill in the results there. Again, not sure if you can return a ModelAndView or use #ResponseBody to return XML/JSON, but I am sure you can.
Short background about DeferredResult:
Your controller is eventually a function executed by the servlet container (for that matter, let's assume that the server container is Tomcat) worker thread. Your service flow start with Tomcat and ends with Tomcat. Tomcat gets the request from the client, holds the connection, and eventually returns a response to the client. Your code (controller or servlet) is somewhere in the middle.
Consider this flow:
Tomcat get client request.
Tomcat executes your controller.
Release Tomcat thread but keep the client connection (don't return response) and run heavy processing on different thread.
When your heavy processing complete, update Tomcat with its response and return it to the client (by Tomcat).
Because the servlet (your code) and the servlet container (Tomcat) are different entities, then to allow this flow (releasing tomcat thread but keep the client connection) we need to have this support in their contract, the package javax.servlet, which introduced in Servlet 3.0 . Spring MVC use this new Servlet 3.0 capability when the return value of the controller is DeferredResult or Callable, although they are two different things. Callable is an interface that is part of java.util, and it is an improvement for the Runnable interface. DeferredResult is a class designed by Spring to allow more options (that I will describe) for asynchronous request processing in Spring MVC, and this class just holds the result (as implied by its name) while your Callable implementation holds the async code. So it means you can use both in your controller, run your async code with Callable and set the result in DeferredResult, which will be the controller return value. So what do you get by using DeferredResult as the return value instead of Callable? DeferredResult has built-in callbacks like onError, onTimeout, and onCompletion. It makes error handling very easy. In addition, as it is just the result container, you can choose any thread (or thread pool) to run on your async code. With Callable, you don't have this choice.
Here you can find a simple working examples I created with both options, Callable and DeferredResult.

Resources