ardatan / graphql-mesh

🕸️ GraphQL Federation Framework for any API services such as REST, OpenAPI, Swagger, SOAP, gRPC and more...
https://the-guild.dev/graphql/mesh
MIT License
3.26k stars 333 forks source link

Hive Gateway subscriptons not working #7673

Open klys-equinix opened 5 days ago

klys-equinix commented 5 days ago

Issue workflow progress

Progress of the issue based on the Contributor Workflow

Make sure to fork this template and run yarn generate in the terminal.

Please make sure Mesh package versions under package.json matches yours.


Describe the bug

Graphql subscriptions do not work. If i try to run the subscription through GraphiQL, the response is 404

Screenshot 2024-09-12 at 10 09 13

The OpenTelemetry logs are as follows:

{
resource: {
attributes: {
'service.name': 'Gateway',
'telemetry.sdk.language': 'nodejs',
'telemetry.sdk.name': 'opentelemetry',
'telemetry.sdk.version': '1.25.1',
'process.pid': 6,
'process.executable.name': 'node',
'process.executable.path': '/usr/local/bin/node',
'process.command_args': [ '/usr/local/bin/node', '/serve/bin.mjs', 'supergraph' ],
'process.runtime.version': '22.8.0',
'process.runtime.name': 'nodejs',
'process.runtime.description': 'Node.js',
'process.command': '/serve/bin.mjs',
'process.owner': 'node',
'host.name': 'hive-gateway-external-66984f7fd-5w5hb',
'host.arch': 'amd64'
}
},
instrumentationScope: { name: 'gateway', version: undefined, schemaUrl: undefined },
traceId: '5a5a8607eaa73a972e9cf13cb7f104e7',
parentId: undefined,
traceState: undefined,
name: 'GET /gateway/graphql',
id: 'a2a1816dfb7b25ec',
kind: 1,
timestamp: 1726128168069000,
duration: 2460.951,
attributes: {
'http.method': 'GET',
'http.url': 'http://localhost/gateway/graphql?query=subscription+test%7BinventoryEvents%7B...on+CabinetStatusChangedEvent%7BeventId+cabinetId+previousStatusId+currentStatusId%7D...on+CageStatusChangedEvent%7BeventId+cageId+previousStatusId+currentStatusId%7D%7D%7D&operationName=test&extensions=%7B%7D',
'http.route': '/gateway/graphql',
'http.scheme': 'http:',
'net.host.name': 'localhost',
'http.host': 'localhost',
'http.client_ip': '10.249.0.4',
'http.user_agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:130.0) Gecko/20100101 Firefox/130.0',
'http.status_code': 404
},
status: { code: 2, message: 'Not Found' },
events: [],
links: []
} 

Queries for the same subgraph that provides this subscription work correctly.
Subscribing directly to subgraph works correctly

**To Reproduce** Steps to reproduce the behavior:

Run Hive Gateway with at least one subgraph implementing subscriptions using websocket transport.
Configure Hive Gateway with endpoint:

gateway.config.ts: | import {defineConfig, type WSTransportOptions, createStdoutExporter} from '@graphql-hive/gateway'

export const gatewayConfig = defineConfig({
  transportEntries: {
    // use "*.http" to apply options to all subgraphs with HTTP
    '*.http': {
      options: {
        subscriptions: {
          kind: 'ws',
          location: '/graphql'
        } satisfies WSTransportOptions
      }
    }
  },
  openTelemetry: {
    exporters: [
      // A simple output to the console.
      // You can add more exporters here, please see documentation below for more examples.
      createStdoutExporter()
    ],
    spans: {
      http: true, // Whether to track the HTTP request/response
      graphqlParse: true, // Whether to track the GraphQL parse phase
      graphqlValidate: true, // Whether to track the GraphQL validate phase
      graphqlExecute: true, // Whether to track the GraphQL execute phase
      subgraphExecute: true, // Whether to track the subgraph execution phase
      upstreamFetch: true // Whether to track the upstream HTTP requests
    }
  }
})


**Expected behavior**

Subscriptions work correctly

**Environment:**

- OS:
- Hive Gateway Docker
ardatan commented 5 days ago

Could you give more details about your subgraphs? Do they use graphql-ws protocol? Or maybe they use the legacy subscriptions-transport-ws?

klys-equinix commented 5 days ago

There is only one subgraph serving subscriptions. It is based on graphql-ws protocol

https://docs.spring.io/spring-graphql/reference/transports.html#server.transports.websocket

But it seems like the gateway is not even trying to call it

ardatan commented 5 days ago

Have you tried to make the HTTP request with curl or some other http client?

klys-equinix commented 5 days ago

I tried making a request with Postman GraphQL client. There is says that gateway responded with incorrect response code 200 instead of 101

Screenshot 2024-09-12 at 18 23 45

Here are the logs from this request

{ resource: { attributes: { 'service.name': 'Gateway', 'telemetry.sdk.language': 'nodejs', 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': '1.25.1', 'process.pid': 6, 'process.executable.name': 'node', 'process.executable.path': '/usr/local/bin/node', 'process.command_args': [ '/usr/local/bin/node', '/serve/bin.mjs', 'supergraph' ], 'process.runtime.version': '22.8.0', 'process.runtime.name': 'nodejs', 'process.runtime.description': 'Node.js', 'process.command': '/serve/bin.mjs', 'process.owner': 'node', 'host.name': 'hive-gateway-external-7664cc5d55-89g5m', 'host.arch': 'amd64' } }, instrumentationScope: { name: 'gateway', version: undefined, schemaUrl: undefined }, traceId: '4fce12dacd20a8c23d04f77f0cdddbf9', parentId: undefined, traceState: undefined, name: 'GET /gateway/graphql', id: 'c16e61a8e3b4aaaf', kind: 1, timestamp: 1726157965615000, duration: 732.977, attributes: { 'http.method': 'GET', 'http.url': 'http://localhost/gateway/graphql', 'http.route': '/gateway/graphql', 'http.scheme': 'http:', 'net.host.name': 'localhost', 'http.host': 'localhost', 'http.client_ip': '10.249.0.4', 'http.user_agent': 'PostmanClient/undefined (AppId=6217ee3f-4ef9-4f3d-b10a-c0582107b1ea)', 'http.status_code': 200 }, status: { code: 1, message: undefined }, events: [], links: [] }

klys-equinix commented 5 days ago

Can you give me an example of correct curl for querying subscription on gateway?

ardatan commented 5 days ago
curl 'http://localhost:4000/graphql' \
  -H 'accept: text/event-stream' \
  -H 'content-type: application/json' \
  --data-raw '{"query":"subscription OnProductPriceChanged { productPriceChanged { name price reviews { score } } }","operationName":"OnProductPriceChanged"}'

You can initiate an SSE connection as in here with curl.

Regarding the error in the screenshots you shared above; In there, you are trying to connect the gateway via WebSockets not SSE. We only support the actively developed graphql-ws only not deprecated subscriptions-transport-ws . I am not sure which one Postman uses there.

klys-equinix commented 4 days ago

Hi, I tried forming the request like in the curl you described. This resulted in error:

event: next
data: {"errors":[{"message":"Cannot find package '@graphql-mesh/transport-ws' imported from /node_modules/.chunk/createGatewayRuntime-DfdVdZl2.mjs","locations":[{"line":1,"column":20}],"path":["inventoryEvents"]}]}

event: complete
data:

And in the logs:

[2024-09-13T09:21:43.876Z] DEBUG vdc-inventory-service - 430ed7d622f261c84c120254f2868472 subgraph-execute {
query: 'subscription test2{inventoryEvents{__typename ...on CabinetStatusChangedEvent{eventId}}}',
variables: {}
}
[2024-09-13T09:21:43.876Z] DEBUG Loading transport "ws" for subgraph vdc-inventory-service
[2024-09-13T09:21:43.877Z] HOOKS Trying default resolve for "@graphql-mesh/transport-ws"
[2024-09-13T09:21:43.879Z] DEBUG Processing GraphQL Parameters done.
[2024-09-13T09:21:43.878Z] HOOKS Trying default resolve for "@graphql-mesh/transport-ws" failed; trying alternatives
[2024-09-13T09:21:43.878Z] HOOKS Trying "@graphql-mesh/transport-ws.ts" 

This likely means two things:

  1. The docker image is missing the transport-ws package
  2. The GraphiQL provided with the Gateway is not compatible with how the Gateway handles subscriptions