graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

HotChocolate: Subscription errors are swallowed

Open hognevevle opened this issue 3 years ago • 2 comments

Describe the bug If an exception occurs in the subscription backend (for example related to the JSON serialization done during the Redis transport), the HC Server will simply swallow the error, and the subscription will be terminated.

On the client side, an error like this will be seen: [GraphQL error]: Message: Unexpected Execution Error, Location: undefined, Path: undefined

On the server side, nothing - even if you have configured an errorfilter.

To Reproduce Configure a subscription, subscribe to it, then publish a message to the topic containing an object that fails serialization (in my case, an object with a property of type JsonDocument).

Expected behavior Properly propagating the exception, so that it can be picked up by IErrorFilter, for example.

Additional context The only current option AFAIK that allows you to catch such errors, is to make the subscription resolver very verbose like the below:

            var stream = await eventReceiver.SubscribeAsync<string, Foo>(
                "foo-topic", cancellationToken);

            var enumerator = stream.ReadEventsAsync().GetAsyncEnumerator(cancellationToken);
            var hasResult = true;
            
             while (hasResult)
             {
                 Foo? result;
                 try
                 {
                     hasResult = await enumerator.MoveNextAsync().ConfigureAwait(false);
            
                     result = hasResult 
                         ? enumerator.Current 
                         : null;
                 }
                 catch (Exception ex)
                 {
                     result = null;
                 }
                 if (result != null)
                 {
                     yield return result;
                 }
             }
            

hognevevle avatar Apr 15 '21 21:04 hognevevle

This also happens when using IObservable and the IObservable rises an exception when producing an element. In this specific case, the error is completely swallowed and nothing (nor errors, no null, no connection closing) is sent to the client.

For example, with a subscription in this (fake) form:

public IObservable<Customer> SubscribeToCustomerChanges(long key) {
      return Observable.FromAsync(async ct => {
        try {
          var session = _globalSessionFactory.CreateReadOnlySession();
          return await session.LoadAsync(key, cancellationToken: ct).ConfigureAwait(false);
        }
        catch (CannotLoadObjectsException ex) {
          throw new QueryException(ex.Message);
        }
      });
}

When an invalid key is passed, no error is sent to the client. Using Banana Cake Pop in Asp.Net Core nothing is shown, and the subscription request apparently keeps waiting for other updates. With a valid key, the subscription correctly sends the customer data. This is the sample query:

subscription {
  subscribeToCustomerChanges(key: 9999999) {
    oid,
    name
  }
}

frabe1579 avatar Sep 21 '21 18:09 frabe1579

AFAIK this is still valid. (Commenting to keep issue alive)

hognevevle avatar May 04 '22 08:05 hognevevle

The issue here is that if the message is invalid it never gets to the execution as the error happens on the event stream.

With 13.4 we have improved insights and there os now an error on the diagnostic events.

ISubscriptionDiagnosticEvents.MessageProcessingError(string topicName, Exception error)

Overriding this on the diagnostic listener will allow errors to be captured.

michaelstaib avatar Jul 22 '23 21:07 michaelstaib