question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`GraphQLTransportWSHandler` only supports one connection

See original GitHub issue

Once a client has connected to Ariadne through the GraphQLTransportWSHandler (the newer GraphQL WebSocket protocol), all future attempts to connect by another client will fail, even if the first client has disconnected.

I believe this issue is caused by this section in the code:

https://github.com/mirumee/ariadne/blob/86a87efd9e3714a39f4da97cce92db6748331f2e/ariadne/asgi/handlers/graphql_transport_ws.py#L111-L116

It looks like the transport gets tagged as having received an “init” message, even though it seems like the client should be tagged.

Steps to reproduce

I came up with the following sample GraphQL server to demonstrate this issue (using Ariadne v0.16) as a minimal test case:

import asyncio
from ariadne import gql, make_executable_schema, ObjectType, SubscriptionType
from ariadne.asgi import GraphQL
from ariadne.asgi.handlers import GraphQLTransportWSHandler
from starlette.applications import Starlette
from starlette.routing import Route, WebSocketRoute
import uvicorn

type_defs = gql("""
    type Query {
        hello: String!
    }

    type Subscription {
        counter: Int!
    }
""")

query = ObjectType("Query")

@query.field("hello")
def hello_resolver(*_):
    return "Hello world"

subscription = SubscriptionType()

@subscription.source("counter")
async def counter_generator(*_):
    for i in range(5):
        await asyncio.sleep(1)
        yield i

@subscription.field("counter")
def counter_resolver(count, *_):
    return count

schema = make_executable_schema(type_defs, subscription)
graphql_app = GraphQL(
    schema,
    debug=True,
    websocket_handler=GraphQLTransportWSHandler(),
)
routes = [
    Route("/graphql", graphql_app, methods=["GET", "POST"]),
    WebSocketRoute("/graphql", endpoint=graphql_app),
]
app = Starlette(debug=True, routes=routes)

if __name__ == "__main__":
    uvicorn.run(app, host='0.0.0.0', port=4444)

After creating a file with that script and starting the server with main.py, I then used websocat to manually trigger the error. First, I connected to the server, manually sent the “connection init” message, then pressed Ctrl-D to disconnect after receiving a “connection ack” message:

$ websocat --protocol 'graphql-ws' 'ws://localhost:4444/graphql'
{"type": "connection_init"}
{"type": "connection_ack"}
^D

Then, I did the same thing as a new client, but did not get the “connection ack”, indicating that the connection was rejected:

$ websocat --protocol 'graphql-ws' 'ws://localhost:4444/graphql'
{"type": "connection_init"}

Running websocat -vv ... will also show that an error code of 4429 was returned, which lines up with the error code from the graphql_transport_ws.py file linked above.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
rafalpcommented, Sep 26, 2022

I’m releasing a fix as 0.16.1, thanks everyone!

0reactions
kylewlacycommented, Sep 17, 2022

@kylewlacy I’ve released 0.16.1.b1 with changes that should fix this. Can you please verify when you have time and let me know? Thanks!

Sure thing, I just tried out the v0.16.1.b1 release from PyPI and from all my testing, it looks like I am able to connect with multiple different clients now! So from my perspective, that release resolves my issue.

Thanks for coming to such a quick resolution for this issue @rafalp and @pigletto!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Subscriptions in Apollo Server - Apollo GraphQL Docs
Each subscription operation can subscribe to only one field of the Subscription type. Enabling subscriptions. Subscriptions are not supported by Apollo Server ...
Read more >
How to restart connection with new connection params? #171
A simple solution for this issue is to use a function instead of object for connectionParams , and the transport will call the...
Read more >
GraphQL over WebSockets – The Guild
Doing a basic Google search, you'd be faced with a single solution, namely subscriptions-transport-ws . Looking through the repository, ...
Read more >
graphql-ws - npm
Start using graphql-ws in your project by running `npm i graphql-ws`. ... fastify.get('/graphql', { websocket: true }, makeHandler({ schema } ...
Read more >
Quirks of GraphQL Subscriptions: SSE, WebSockets, Hasura ...
GraphQL client and server implementations don't usually support content negotiation. The reason being that for a long time, there was just one ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found