DjangoChannelsGraphqlWs icon indicating copy to clipboard operation
DjangoChannelsGraphqlWs copied to clipboard

Notify subscriptions on closed socket

Open jordanmarkov opened this issue 4 years ago • 5 comments

Hello,

I need to run some cleanup code when a clent unsubscribes or disconnects. Function similar to unsubscribed(root, info, *args, **kwds) for the case when a client disconnects would be perfect. Is this possible?

jordanmarkov avatar Jan 19 '21 06:01 jordanmarkov

Dear @jordanmarkov,

GraphqlWsConsumer has on_connect method to handle the connection event. Probably we should add on_disconnect there to handle disconnect, e.g. to cleanup something. What do you think? Will this address your need?

prokher avatar Feb 11 '21 22:02 prokher

Hello @prokher ,

Not really. I would need the arguments for the subscription. I came up with some not really good solution, but it works for my use case. The problem is it uses private members:

class GraphQLWsConsumer(channels_graphql_ws.GraphqlWsConsumer):
    # ...

    async def disconnect(self, code):
        self._assert_thread()
        for sid in self._subscriptions:
            subinf = self._subscriptions[sid]
            await self._run_in_worker(subinf.unsubscribed_callback)
        await super().disconnect(code)

    # ...

class MySubscription(channels_graphql_ws.Subscription):
    class Arguments:
        arg1 = graphene.String(required=True)

    @staticmethod
    async def subscribe(_root, _info, arg1):
        # setup

    @staticmethod
    async def unsubscribed(_root, _info, arg1):
        # cleanup

Something along these lines would be perfect, possibly with another callback, but I don't really care in this case if the client has disconnected or unsubscribed.

jordanmarkov avatar Feb 12 '21 08:02 jordanmarkov

We really need this as well, we have some tidy up to do when a client disconnected on a per subscription based, right now we're trying to hack it together using the functions above, but it would be much nicer to be baked into the library.

matclayton avatar Nov 01 '21 12:11 matclayton

So it is not possible at the moment?

My use case is that I need to set the user as offline for a specific chatroom, therefore accessing the arguments of the subscription.

It would be good to have the on_disconnect in the consumer as well. But for this specific use case, it won't work unless I have access to the subscription payload.

Meanwhile, I implemented the solution from above.

btribouillet avatar Nov 30 '21 01:11 btribouillet

This is effectively what we've done, incase it helps someone

class GraphQLWsConsumer(channels_graphql_ws.GraphqlWsConsumer):
    async def disconnect(self, code: int) -> None:
        """
        This handles firing off the unsubscribe functions on subscriptions
        when a client is disconnected, e.g. when they close the browser
        See https://github.com/datadvance/DjangoChannelsGraphqlWs/issues/62
        """
        self._assert_thread()

        # Fire of a GQL Stop (and therefore unsubscribe) for any active subscriptions
        # This is necessary as the library doesnt do this by default.
        for sid in self._subscriptions.copy():
            await self._on_gql_stop(sid)

        await super().disconnect(code)

matclayton avatar Nov 30 '21 12:11 matclayton