ServerEvents not received on client

Hello

I wanted to avoid sending OnJoin and OnLeave events to all clients, but when I set NotifyChannelOfSubscriptions to false clients do not receive any channel messages.
When not set, clients receive both subscriptions events and channel messages.

Server: ServiceStack 6.0.2, client: dart, communication: gRPC.

public class ConfigureServerEvents : IHostingStartup
{
	public void Configure(IWebHostBuilder builder) => builder
		.ConfigureAppHost(appHost => {
			appHost.Plugins.Add(new ServerEventsFeature
			{
				//NotifyChannelOfSubscriptions = false
			});
		});
}

Hi @masterit,

How is your AppHost currently hosted? Eg, on IIS, Kestrel etc?

Could you share the client code you are using to connect to the StreamServerEvents?

Something to try on the server is to specify the MemoryServerEvents.FlushNopOnSubscription = false to see if you get all the expected messages or not.

Thanks

Thanks for quick response.

When both NotifyChannelOfSubscriptions = false and MemoryServerEvents.FlushNopOnSubscription = false messages are received on clients.

Is this just temporary solution or this is preferred setting? Does same applies to HTTP and gRPC?

As per request, below is my dart code:

final channelOptions = message.cloudProtocol == "http"
	? const ChannelOptions(credentials: ChannelCredentials.insecure())
	: ChannelOptions(
		credentials: ChannelCredentials.secure(
		  certificates: message.certifiate.buffer.asUint8List(),
		),
	  );

_grpcCient = GrpcServicesClient(
  ClientChannel(
	message.cloudUrl,
	port: message.cloudPortGrpc,
	options: channelOptions,
  ),
);



final serverEventRequest = StreamServerEvents()
        ..channels.add(message.pib);
final stream = _grpcCient.serverStreamServerEvents(serverEventRequest);

await for (var r in stream) {
  print("${DateTime.now()} | ${r.selector} | ${r.json}");
}

Server is selfhost Kestrel on linux behind nginx with following configuration:

server {
    listen 443 ssl http2;
    server_name <SERVER URL>;

    root /var/www/html;

    location / {
        grpc_read_timeout 2h; <- if no serverevents for this period, tunnel is dropped and client reconnects (increased to 2 hours because default is 60 secs)
        grpc_pass grpc://localhost:20002;
    }

    ssl_certificate /home/ubuntu/certs/my.crt;
    ssl_certificate_key /home/ubuntu/certs/my.key;
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/my.access.log;
    error_log /var/log/nginx/my.error.log warn;
}

Kind regards

Thanks or the Info, we’ve added a change on MyGet that prevents sending a NoOp when called from gRPC endpoints which was closing the connection.

This change is now available from the latest v6.0.3 that’s now available on MyGet.

1 Like

Confirming that when using 6.0.3 events and messages work as expected without MemoryServerEvents.FlushNopOnSubscription = false.

public class ConfigureServerEvents : IHostingStartup
{
    public void Configure(IWebHostBuilder builder) =>
        builder
            .ConfigureAppHost(appHost =>
            {
                appHost.Plugins.Add(new ServerEventsFeature
                {
                    NotifyChannelOfSubscriptions = false
                });
            });
}

I’m having a problem how to detect on client side (dart) that serverevent stream is broken.
I know that this is most likely not related to ServiceStack, but maybe you would share any experience on this?

Kind regards

The behavior of gRPC proxy generated clients is beyond our control, but to help searching about it, in gRPC terminology the feature used to return the sever events is called “Server streaming RPC”:

In general the App-level technique to verify long-lived connections aren’t broken is to send heartbeats or keep-alives, i.e. clients sends a periodic heartbeats which if it doesn’t receive a response within a specific time period, the connection is considered broken and it auto reconnects to establish a new connection.

Ofcourse, I have done search, but found that dart-grpc team does not plan to implement heartbeat.

Thanks, anyway

It’s a high-level App feature that I don’t expect to be implemented in client libraries since it requires spawning and managing a background thread or timer that has to auto reconnect your App’s client connections. But that’s the approach I’d personally take if I wanted to detect whether long-running persistent connections are still active.