Closed ajnfde closed 4 years ago
When you use the publisher approach you can add an event listener method into your code. This method then receives every message you send in your application.
@Service
public class MyService {
private final ApplicationEventPublisher eventPublisher;
public void broadcastEvent() {
this.eventPublisher.publishEvent(SseEvent.ofData("some useful data"));
}
@EventListener
public void handleEvent(SseEvent event) {
// do something here
}
}
When you use the other approach there is currently no way to log the messages.
@Service
public class DataEmitterService {
private final SseEventBus eventBus;
public void broadcastEvent() {
this.eventBus.handleEvent(SseEvent.ofData("some useful data"));
}
}
We could solve this by either adding log statements to the library or adding some lifecycle hooks. Hooks could be interesting not only for logging but also for statistic tracking.
With the new version 1.1.8 you can now install a lifecycle listener
public class MyListener implements SseEventBusListener {
/** An event has been added to the internal queue */
@Override
public void afterEventQueued(ClientEvent clientEvent, boolean firstAttempt) {
}
/** An event has been sent to the client.
exception -> null: event has been sent successfully
exception -> not null: an error has occurred during sending
*/
@Override
public void afterEventSent(ClientEvent clientEvent, Exception exception) {
}
/** Library has removed one or multiple stale clients */
@Override
public void afterClientsUnregistered(Set<String> clientIds) {
}
}
@SpringBootApplication
@EnableSseEventBus
public class MyConfiguration implements SseEventBusConfigurer {
@Override
public SseEventBusListener listener() {
return new MyListener();
}
This should give an application a bit more insight into the internal workings of the libraries and I hope helps for tracking errors.
When an error has occurred during sending the event, is the event discarded or saved in the queue?
The library stores failed messages into a queue and tries to send them again.
By default the library tries to send failed messages every 500 milliseconds and it does that 40 times. After 40 failed send tries it discards the message. You can configure these parameters with the configurer.
The afterEventQueued
hook should be called each time a message is added because of a failure.
Thank you @ralscha for your answer. In production, it seems to us, in certain conditions, many messages stay in the the sendQueue. We want to understand if there was a problem which causes this sendQueue state or if it is large memory used by the queue which causes the JVM error.
You find the code for the event loop here: https://github.com/ralscha/sse-eventbus/blob/master/src/main/java/ch/rasc/sse/eventbus/SseEventBus.java#L264-L292
In my productive app I use the defaults of 40 retries and 500ms between retries but I shortened the client expiration parameters.
@Configuration
public class SseEventBusConfiguration implements SseEventBusConfigurer {
@Override
public Duration clientExpiration() {
return Duration.ofMinutes(30); // default 1 day
}
@Override
public Duration clientExpirationJobDelay() {
return Duration.ofMinutes(5); // default 1 da
}
}
I suggest you some improvements:
Set Client class public
Log the errors in the eventLoop
method. When there is an exception, the thread which is runnig eventLoop
method completes. The sendQueue grows and the events are not more consumed.
It is the same thing for the reScheduleFailedEvents
method
I wonder what exceptions could occur in these methods. In reScheduleFailedEvents
only two method calls throw exceptions: .drainTo
and .put
These two calls could throw: InterruptedException
, UnsupportedOperationException
, ClassCastException
, NullPointerException
and IllegalArgumentException
.
Unsupported, class cast and null pointer are never possible I guess. Interrupted exception is handled. The only question is the illegal argument exception. Not sure in what situation this exception can occur.
@ralscha I agree with you about the risk to get an exception. But we got a outOfMemory in our back application. A snapshot of the JVM showed us the sendQueue took more than 200 MB. We don't have any explanation of that.
- Set Client class
public
- Log the errors in the
eventLoop
method. It is the same thing for thereScheduleFailedEvents
method
Released 1.1.9 with these changes.
When we create an emitter with the method
createSseEmitter(String clientId, String... events)
ofSseEventBus
class, we cannot log the messages really published.In our case, we want to know if it our back app which doesn't publish some events or if it is our front app (angular 8) which has a trouble in the message reception.