smallrye / smallrye-graphql

Implementation for MicroProfile GraphQL
Apache License 2.0
153 stars 88 forks source link

TypeSafe graphql client websocket never closed #2086

Open ITrium-Salah opened 2 months ago

ITrium-Salah commented 2 months ago

To my knowledge, there is no "simple" way to close the websocket used for the graphql client. I have a problem during a logout operation where I cancel all subscriptions but my application continues to receive notifications. "Received data for already canceled operation 1". This raises two problems for me:

  1. why the server continues to notify messages when it is supposed to have received a completion message for the id of the subscription.
  2. And how to force the graphql client to release its resources and close the websocket if you want to operate a login/logout function for example.
jmartisk commented 2 months ago
  1. When you subscribe to a Multi, you get back a io.smallrye.mutiny.subscription.Cancellable which you can use to cancel a subscription, and then you should no longer receive any data for it - you can turn on TRACE logging on io.smallrye.graphql.client to see the client send a cancellation request to the server. Is this not working for you?

  2. If your typesafe API interface is declared to implement Closeable and then you call close() on an instance of it, it should cancel all subscriptions and close the websocket connection.

ITrium-Salah commented 2 months ago

@jmartisk Yes i have cancelled all subscriptions but i'm still receiving data from the server and the websocket seems to stay open after. Do you know a way to check for subscriptors programmaticallay? And i have this message after i cancel all subscription: "Received data for already canceled operation 1". This make me thing that my cancel work fine but the server or client is keeping the link opened

ITrium-Salah commented 2 months ago

@jmartisk Yes i have cancelled all subscriptions but i'm still receiving data from the server and the websocket seems to stay open after. Do you know a way to check for subscriptors programmaticallay? And i have this message after i cancel all subscription: "Received data for already canceled operation 1". This make me thing that my cancel work fine but the server or client is keeping the link opened

By the way, my graphql client interface is split in more than one interface (for readability and maintenance)

ITrium-Salah commented 2 months ago

@jmartisk Can you confirm me that by default the client do not use the websocket to send query or mutation and there is no risk that the websocket is kept open to send the queries/mutations?

jmartisk commented 2 months ago

@jmartisk Yes i have cancelled all subscriptions but i'm still receiving data from the server and the websocket seems to stay open after.

Cancelling all subscriptions isn't enough, you have to close the client to close the websocket.

Do you know a way to check for subscriptors programmaticallay? And i have this message after i cancel all subscription: "Received data for already canceled operation 1". This make me thing that my cancel work fine but the server or client is keeping the link opened

There is no straightforward way to programmatically get the list of active subscriptions on the server, but from the TRACE log on the server, it should be clear that the server stops the subscription and sends a confirmation to the client (that there will be no more messages for this particular subscription ID).

Note that the client might log that message Received data for already canceled operation 1 sometimes due to a race condition - the client tells the server to stop the subscription, but an event occurs and is sent before the server can process this command. Are you sure this isn't the case? If it keeps sending even after that after some circumstances, it might be a bug and I'd like to see a reproducer if possible

By the way, my graphql client interface is split in more than one interface (for readability and maintenance)

Then each interface keeps its own websocket and you have to close all of them to close all the websockets

Can you confirm me that by default the client do not use the websocket to send query or mutation and there is no risk that the websocket is kept open to send the queries/mutations?

Right, by default, queries and mutations are executed over POST HTTP requests, unless you set quarkus.smallrye-graphql-client."CLIENT_NAME".execute-single-result-operations-over-websocket=true

ITrium-Salah commented 2 months ago

My code is quite complex to produce a reproducible example. I think that maybe a subscription is still alive. I will merge all my graphql subscription into one graphql client and implement the closeable interface. Then i will check if i have the same behavior.

ITrium-Salah commented 2 months ago

@jmartisk Can i reuse a graphql client after calling close on it? If not how i can "reset" my graphql client after closing it?

jmartisk commented 2 months ago

A closed client can't be resurrected. You'll need to use the VertxTypesafeGraphQLClientBuilder to build a new instance...

If you use a configured client injected via CDI, it wasn't really designed to be closed at any point (and if the underlying websocket connection crashes, the client automatically attempts to recreate it)