ServerEvents constant error re subscriptions

Exception details: ResponseStatus { ErrorCode: “NotFound”, Message: “Subscription QFhSkkJQX5uCNZLUyRnA does not exist”, StackTrace: null, Errors: [], Meta: null }

What do I have to hook into to stop having these constantly in my logs? Is there a handler I can look for?

every 15 minutes i called this:

((RedisServerEvents)Instance.Resolve()).UnRegisterExpiredSubscriptions();

i tried this as well (OnHeardBeatInit), but alas, it did nothing.

Plugins.Add(new ServerEventsFeature
    {
        OnHeartbeatInit = req =>
        {
            var subscriptionId = req.QueryString["id"];
            var subscription = req.TryResolve<IServerEvents>().GetSubscriptionInfo(subscriptionId);
            if (subscription == null)
            {
                //... subscription no longer exists
                req.Response.Close();
            }
        },
            
        OnConnect = ((subscription, dictionary) =>
        {
            Serilog.Log.Information("Connect from {Addr} for {User}",subscription.UserAddress,subscription.UserName);
        }),
        
        OnError = (subscription, exception) =>
        {
            Serilog.Log.Warning("Server event error! Message: {Message}",exception.Message);
        }
        ,LimitToAuthenticatedUsers = true,
        NotifyChannelOfSubscriptions = false,
    });
    
    container.Register<IServerEvents>(c =>
        new RedisServerEvents(c.Resolve<IRedisClientsManager>()));
    container.Resolve<IServerEvents>().Start();

Just want to confirm you are seeing these errors in your server or client logs? Also helpful information

  • Which ServiceStack version are you running?
  • What is your logging setup?

It looks like the message is from the client requesting to unregister with a subscription ID that has already been removed/cleaned up on the server.

What client library are your clients connecting with?

The server is just throwing a 404, is it being output at the ‘ERROR’ level or lower? Depending on how you logging is setup, you could filter at the logging level.

6.0.2 across the board, in .net 6.0 as well
Logging is serilog to seq

i am hoping for a way to just ignore it. i can add a filter to just not report it but was hoping for a way to do it inside ss. where is the best place to catch this? something like

public override void OnExceptionTypeFilter

??

client library is also SS 6.0.2 and client is IServiceClient, using JsonHttpClient

when app starts, i am doing auto with server events, on exit, i logout, then close.

it is throwing an error.

I assume Serilog is wired up to the standard ILoggerFactory etc in ASP.NET core?

ServiceExceptionHandlersAsync can pick up the error and return something else, but is a hack, filtering in your logging setup would be a better idea. However, for completeness, it would be something like

this.ServiceExceptionHandlersAsync.Add(async (req, request, exception) =>
{
    if (request is UnRegisterEventSubscriber && exception is HttpError { StatusCode: HttpStatusCode.NotFound })
    {
        return DtoUtils.CreateResponseDto(request, null);
    }
    return null;
});

If you return another error response using DtoUtils.CreateErrorResponse, you’ll just get a different message in your logs.

Could you share your ServerEventsClient usage? Using client.Stop() and disposing I can’t replicate the consistently throwing this error, though I’m not testing with authentication. Is it possible the client is making multiple calls to event-unregister? Can you see in your logs a multiple in quick succession with the same subscription ID? If the error is so frequent, I think might be sign of another issue.

i generally use Serilog.Log static for most things, but I do have some ILoggerFactory stuff in places

on startup

eventClient = new ServerEventsClient(url)
await eventClient.AuthenticateAsync(new Authenticate
        {
            UserName = Credential.Username, Password = Credential.Password, provider = "Credentials",
            RememberMe = true
        });

this is AFTER the main client auths as well, for jsonhttpclient

when client is closing:

eventClient?.ServiceClient.Post(new Authenticate { provider = "logout" });
eventClient?.Stop();

Client.Post(new Authenticate { provider = "logout" });

it looks like things have calmed down now that i have added some of my later code and let things normalize. i was curious if this was something that could be ignored or if i had implemented things incorrectly

i turned on debug logging as well so ill see if i can spot anything coming in twice for unsubscribe.

so as is, i see TWO connect events firing when my client starts up.

i removed the explicit call to eventClient.authenticateAsync

and added

EventStreamRequestFilter = req => req.AddBearerToken(txtApiKey.Text),

to the handler:

eventClient = new ServerEventsClient(_newApiUrl) {
            EventStreamRequestFilter = req => req.AddBearerToken(api),

            OnMessage = message =>
            {
                var msg = message.Json.FromJson<ServerEventsMsg>();

                Log.Information("API message: {Message}",msg.Message.TrimStart('"').TrimEnd('"'));
                
            }

        };

and now i see a single connect message from the server. dunno if 2 connects results in 2 subscriptions, but ill see what this ends up looking like long term

the docs are not clear on how/when auth happens. it seems to happen on authasync, but does it also happen again on the call to .Start? if so, should it?

same thing with .Stop(). does it logout explicitly, or do i need to POST a logout?

Yeah each Connect creates a unique subscription. req.AddBearerToken() will be able to Authenticate the event stream to establish an Authenticated Server Events connection.

If you use a bearer token it’s attached to the request that establishes a SSE connection. ServicStack’s built-in Auth Providers that accept Bearer Tokens are stateless, logging out is unnecessary.

ok so just to be clear. i get api key from server.

i have a jsonhttp client that uses this api key for general SS work.

i then have a server events client that uses the api key.

calling .start() will auth to the eventserver and things work since it has the api key

when i call .close() on eventserverclient, does that unsubscribe, or do i still need to logout to remove the subscription?

thanks for the clarification

When you Stop/Dispose the Server Events client it will send an explicit unregister request to terminate the SSE connection on the server.

Logging out isn’t what keeps the Server Events connected, calling the explicit UnRegisterUrl from the server is what terminates it immediately (called on Stop/Dispose), otherwise the server will remove the connection itself when the heartbeat times out.

Also there’s no way to “logout” stateless bearer token which keeps no server session state, i.e. it becomes invalid when it expires (when using JWT).

1 Like