Subscriptions error on Hasura GraphQL Engine deployed with Cloudfoundry on AWS - graphql

Hasura GraphQL Engine is deployed on a Cloudfoundry instance backed by AWS, it is exposed at a subdomain via an AWS ELB. The console is exposed at https://hasura.cloud.domain.com/console and the GraphQL API accepts queries at https://hasura.cloud.domain.com/v1alpha1/graphql.
But when a subscription is executed from console, an error happens with the following log on JS Console:
vendor.js:1 WebSocket connection to 'wss://hasura.cloud.domain.com/v1alpha1/graphql' failed: Error during WebSocket handshake: Unexpected response code: 200
Analyzing the websocket frames on Chrome indicates an error with (Opcode -1).
Basically, the client is unable to open a websocket connection.

Some load balancers do not support passing WebSocket handshake requests containing the Upgrade header to the CF router. For instance, the Amazon Web Services (AWS) Elastic Load Balancer (ELB) does not support this behavior. In this scenario, you must configure your load balancer to forward TCP traffic to your CF router to support WebSockets.
ref: https://docs.cloudfoundry.org/adminguide/supporting-websockets.html#config
Basically, there is some configuration required with AWS ELB and CF Router to get websockets working. This is typically done by setting up a non-standard port to forward all TCP connections to the CF Router. We have learned from our clients that this port is typically 4443.
So, to get websocket connections to work, choose the endpoint as wss://hasura.cloud.domain.com:4443/v1alpha1/graphql for websocket connections and thus subscriptions.
The console can be opened at https://hasura.cloud.domain.com:4443 as well.

Related

Unable to establish a websocket connection for GraphQL subscription

I am trying to implement a GraphQL WebSocket-based #subscription on a server (using NestJS #subscription). The server is hosted on an AWS ECS and is behind an ALB.
We currently have an AWS API GW connection via VPC-link to our ALB.
I tried to build a dedicated Websocket API GW with the same VPC link we use in the HTTP API GW.
I also tried to spin up a new NLB (Network Load Balancer) over our ECS and a new REST VPC link to be used in the dedicated Websocket API GW.
The client and server are communicating over a graphql-transport-ws sub-protocol using graphql-ws library and the communication is working fine on a localhost setup.
When running the following command on our local host I am able to establish a web socket connection:
wscat -c ws://localhost:3000/graphql -s graphql-transport-ws
When running the same against the WebSocket API GW URL
wscat -c wss://*****.execute-api.*****.amazonaws.com/**** -s graphql-transport-ws
I’m getting this:
error: Server sent no subprotocol
The error indicates a problem with the sub-protocol so when removing the sub-protocol a connection is established and I am getting a prompt:
Connected (press CTRL+C to quit)
>
However, there’s no indication of reaching the server and it seems like the connection is only made with the WebSocket API GW itself.
When I circumvent the gateway and directly connect an internet-facing NLB I'm able to establish a WebSocket connection.
I am not a super Websocket expert, but I understand WebSocket connections will be terminated by the API Gateway and cannot be used as a connection pass-through. You can forward web socket events using AWS_PROXY integration to a graphQL server backend, BUT it's not a maintained direct connection - API Gateway terminates and events towards the backend integration and will not return the integration response to the WebSocket since it is event-driven and not a connection-oriented service - hence the “error: Server sent no subprotocol” you are seeing.
So to use API GW as the WebSocket layer, you would need to build out connection management functionality somewhere to manage the event-based nature of the APIGW and send out data to the APIGW connections or adjust the integration mechanism within the graphql server to utilise the #connection functionality to send responses/notifications to WebSocket consumers.
Integrating Backend Service documentation:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-routes-integrations.html
Sending responses to a connected client:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html
API GW Websockets are great for building custom solutions but take some effort since you will be configuring the setup for the events.
For a GraphQL API on AWS - I would recommend taking a look at AppSync, which is an AWS Managed GraphQL service - it handles GraphQL subscriptions via WebSockets natively and with zero additional code and its highly scalable out of the box and would simplify the GraphQL hosting burden of an ECS based solution.
I suspect there may be a lot of other reasons for the need to build out using existing GraphQL on ECS, so understand it's not always possible to pivot to something like AppSync. I feel the NLB solution you tried is okay within the existing ECS backend landscape and, as you have noted, is connection-oriented (via NLB), so will achieve the outcome you are after.

WebSocket API gateway connection issue

We are working on the ASP.Net core API application. In this application, we have a SignalR module for notification. We planned to host the application in the AWS environment. We have used the AWS lambda service to host the API, and also the WebSocket API gateway to consume the notification/SignalR part.
We are facing an issue with connecting the notification URL.
When we tried to connect the Web socket URL from Commandline using Node, it is showing "Unexpected server response 403".
When we tried to consume the URL from the frontend application, it showed the below error.
"WebSocket failed to connect. The connection could not be found on the server, either the endpoint may not be a SignalR endpoint, the connection ID is not present on the server, or there is a proxy blocking WebSockets. If you have multiple servers check that sticky sessions are enabled. ."
We are stuck with this issue. Any help to resolve this issue would be appreciable.

Monitoring websocket logs in Azure Gateway

I am aware that Azure application gateway supports websockets. However, I cant figure out from the samples and documentation how websocket access is reflected in the Access Logs.
I have been going over Azure gateway documentation for Access logs over here
https://learn.microsoft.com/en-us/azure/application-gateway/application-gateway-diagnostics#for-application-gateway-and-waf-v2-sku
There is no protocol field - which usually carry ws or wss to indicate websocket access.
Thanks for help in advance
There is no user-configurable setting to selectively enable or disable WebSocket support in Application gateway. WebSocket protocols are designed to work over traditional HTTP ports of 80 and 443. You can continue using a standard HTTP listener on port 80 or 443 to receive WebSocket traffic. WebSocket traffic is then directed to the WebSocket enabled backend server using the appropriate backend pool as specified in application gateway rules.
Here is a clear documentation explaining about Websocket workflow in Application Gateway.

How to properly initiate WebSocket connection with Google Cloud Load Balancer to avoid connection timeout closures?

Utilizing socket.io, my WebSocket connections proxied through the GCLB are closed at the interval defined in the backend service configuration:
Obviously as pictured, the workaround is an impractically long timeout period, but for the sake of correctness, what is the proper way to configure the WebSocket connection through socket.io (or elsewhere if it is not a socket.io's problem) to avoid these closures?
Reason for closure according to GCLB log is "backend_connection_closed_after_partial_response_sent".
As stated in the Cloud Load Balancer documentation it would seem that we need to send a proper Upgrade response in order for the load balancer to keep the connection alive.
When HTTP(S) Load Balancing recognizes a WebSocket Upgrade request from an HTTP(S) client and the request is followed by a successful Upgrade response from the backend instance, the load balancer proxies bidirectional traffic for the duration of the current connection. If the backend does not return a successful Upgrade response, the load balancer closes the connection.
https://cloud.google.com/load-balancing/docs/https/#websocket_proxy_support (emphasis mine)
How can this be done?

Spring Web Sockets over AWS Application Load Balancer not working

I have configured spring with web sockets, including rabbit mq on the back end and I can confirm that I can send push messages to the browser.
And using SockJS on the front end.
Up until now I have been using the classic load balancer.
I am trying to get web sockets to work on AWS. I have upgraded to the Application Load Balancer but I still get Bad Request response when I try to make the web socket connection to:
ws://XXXX.eu-west-1.elasticbeanstalk.com/spring/hello/870/sbmdv5tn/websocket
That call still gives 400 Bad Request response...
And I see
Handshake failed due to invalid Upgrade header: null
Errors on the back end...
It has to do the fact that the a connection upgrade is requested and these upgrade requests occur "per hop".
In my scenario I am running with apache in front of tomcat and in order for tomcat to receive these upgrade headers I need to enable web socket tunnelling on the apache proxy such that apache will simply pass through the upgrade request.
UPDATE:
Although a better solution is to bypass apache altogether and go straight to tomcat - that is configure the load balancer to route to port 8080 and not port 80. I suspect the reason elastic beanstalk does not do this by default because it then requires a load balancer - and if you only want single instance you don't need a load balancer.

Resources