Hi guys, I wonder if anyone can be so kind and help me out a bit with a SSE problem I’ve been tossing my hair about for the past few days.
We got a working SSE solution setup with ServiceStack 5.7.0 for .Net 4.7.2 and Redis cache, the setup looks like this:
Backend:
private void AddServerEventsFeature()
{
var se = new ServerEventsFeature
{
OnCreated = this.OnCreated,
OnSubscribe = this.OnSubscribe, //Just a debug log in this method
OnPublish = (subscription, response, whatever) =>
{
Debug.WriteLine(whatever);
},
HeartbeatInterval = TimeSpan.FromSeconds(10),
IdleTimeout = TimeSpan.FromMinutes(20),
LimitToAuthenticatedUsers = true,
NotifyChannelOfSubscriptions = false
};
AppHost.Plugins.Add(se);
}
private void OnCreated(IEventSubscription eventSub, IRequest request)
{
var session = (MyUserSession)request.GetSession();
if (!session.IsAuthenticated)
{
throw new HttpError(HttpStatusCode.Unauthorized);
}
session.EventsSubscriptionId = eventSub.SubscriptionId;
request.SaveSession(session);
// In case a new subscription is established
// use any existing channels in the session.
eventSub.UpdateChannels(session.Channels ?? new string[0]);
}
Web js SSE initialization:
this.eventSource = new EventSource('/api/event-stream');
this.eventSource.addEventListener('message', this.handleServerSentEvent);
We can see the traffic passing through as it should in OnPublish and OnSubscribe, all is fine and the UI is responsive.
Problem is, when we are simulating an interrupt in the Redis cache communication SSE does not recover from the interrupt. When testing the solution we are using a Docker enabled Redis instance running locally which is working fine, and when we turn it off and on again to simulate the interrupt OnPublish is not triggered anymore and a complete restart of the application is required to get it up and running properly again.
When I turn Redis off it blows up at task.Wait(), in my case at next heartbeat or submitted event when a RedisResponseException “Zero length response” is thrown, followed by with a “SocketException: No connection could be made because the target machine actively refused it 127.0.0.1:6379”, which is expected when Redis is down:
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
{
var task = (Task)result;
task.Wait(); // avoid an exception being thrown on the finalizer thread.
}
However, after the Redis instance is up and running again, I can see that a new subscription is made through OnSubscribe and I guess that is internal ServiceStack behavior, but no more events or heartbeats are being passed anymore, calls are made but none of them seems to be processed.
Even if I reload the page again (it’s a SPA) and retrigger the SSE initialization and it’s preceding event subscriptions, no heartbeats or events are handled by the SSE anymore and it seems like the only way of getting it to work again is to restart the application.
The RedisResponseException is also delivered by the routing after we navigate to another page and that is the most strange part of it all. It does not matter which route we use we still get the RedisResponseException attached to that route, when I feel it should either just be thrown by the SSE API instead of hanging on to the next request?
AppHost.UncaughtExceptionHandlers.Add(HandleUnhandledException);
…
private void HandleUnhandledException(IRequest request, IResponse response, string operationName, Exception exception)
{
/*
The Redis Exception is caught here but only after navigating to other route, which route does not matter, next page navigation will throw the Redis exception which I expected should rather be returned by any of the SSE endpoints?
*/
}
So, any help pointing me in the way of solving this issue would be great since I’ve been searching for answers a lot lately and feel I’m stuck here. It definitely seems like I’m missing an important step here or maybe something is not set up correctly, any ideas how to proceed with this matter?