Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using grapqhl-subscriptions with serverless backend #53

Closed
witbybit opened this issue Mar 29, 2017 · 33 comments
Closed

Using grapqhl-subscriptions with serverless backend #53

witbybit opened this issue Mar 29, 2017 · 33 comments
Labels

Comments

@witbybit
Copy link

How can we use graphql-subscriptions with a serverless backend like AWS Lambda? In this case, transport using web sockets won't work since a lambda function can't run for long time.

@scf4
Copy link
Contributor

scf4 commented Apr 22, 2017

You must have a continuously running server to manage websocket connections. AWS Lambda can handle regular HTTP requests since they're short-lived. Websockets are by definition long-lived.

Edit: It might be possible to run a lambda instance during the lifetime of the websocket, but I can't imagine this would be worthwhile.

@jthegedus
Copy link

jthegedus commented Apr 24, 2017

Given that there are Redis and MQQT subscription packages http://dev.apollodata.com/tools/graphql-subscriptions/external-pubsub.html, are there any tutorials or efforts to create tutorials surrounding the use of managed pubsub services like AWS SNS or GCP PubSub?

Furthermore, as someone using Firebase DB as the storage layer of my GraphQL, is there a way to leverage the real-time part of FirebaseDB through GraphQL on the client?

I am exploring these myself, but curious if others had already attempted this and what the outcome was.

@mattfysh
Copy link

Could you use AWS IoT websockets in front of lambda?

@scf4
Copy link
Contributor

scf4 commented Jun 3, 2017

@jthegedus Any luck so far?

@jthegedus
Copy link

@mattfysh I haven't looked at the AWS IoT websockets service myself. I've used AWS more than GCP but found that GCP PubSub is more generic and therefore easier to understand how it fits into the subscription model.

@scf4 There's a lot of flux with how subscriptions are managed since the finalization of the subscription RFC in the GraphQL spec. I'm trying to keep up with all the changes in the various repos - subscriptions-transport-ws, graphql-js, graphql-subscriptions - to see where exactly the subscriptions state is kept and where a managed pusub service fits. It seems that it should be easier, but the changes are still in progress and there's no point working with the previous implementation as the version built against the spec will be the gold standard implementation.

@dotansimha
Copy link
Contributor

I am not sure this issue has a simple solution.
AWS supports WebSocket connections, and you can combine it with any PubSub implementation (MQTT/Redis).
The main issue here is to keep the connection open with AWS Lambda, because graphql-js (> 0.10.0)graphql-subscriptions and subscriptions-transport-ws can work with any PubSub implementation (just wrap and return AsyncIterator in your GraphQL schema).

@Siyfion
Copy link
Contributor

Siyfion commented Jun 20, 2017

Surely by its very nature, AWS Lambda deals with short lived connections. Websockets aren't short lived. So perhaps AWS Lambda could deal with all the queries and mutations, and an intelligent Application Load Balancer that routes websockets to a single EC2 instance?

@jthegedus
Copy link

jthegedus commented Jun 21, 2017

The solution I am thinking of for this problem isn't trying to get websockets to work in ephemeral compute services (Lambda/Cloud Functions/Azure Functions), it's to move the logic of the connection state to a managed service. A non-websocket pubsub system that enables server to client push of data is what is required. So far from my research, the options from the big 3 include:

Azure: Event Hub or Service Hub
AWS: SQS with SNS (I need to read more about the publish capabilities)
GCP: FCM

The difference with using one of these services to a WS implementation is that the services generally only do server->client data push, so requests to subscribe/unsubscribe and the rest of your GraphQL queries & mutations etc still need to be through a HTTP GraphQL server - personally I like this unidirectional flow of data anyway.

Recently in the GraphQL Radio podcast, ep3 Microsoft guest Erik Schlegel outlined how they are using Azure Event Hub as the data transport for their GraphQL subscriptions - https://youtu.be/crXSN8SKjGI?t=14m58s It is also mentioned that they may be open-sourcing their Azure Event Hub / PubSub Engine wrapper at a later date.

Another issue with this type of system is that the message payload sizes are then dictated by the service being used, which vary from vendor to vendor. GCP Firebase Cloud Messaging is what I am working on atm as I use GCP more than AWS.

@Siyfion
Copy link
Contributor

Siyfion commented Jun 21, 2017

@jthegedus ahh, I see where you're going with this now. So basically someone just needs to write a subscription transport-layer for SNS/FCM/Event Hub (or all three) and then use that for the subscription updates. Interesting!

If only I had a bit more time spare I'd take a look myself... maybe in a few weeks.

@jthegedus
Copy link

jthegedus commented Jun 21, 2017

@Siyfion Precisely, I just happened to start looking into this when significant changes were being made. I'm now just waiting for this to be merged #78 which I think is the last significant change of the subscription related layer at this time.

I'm going to work on the FCM transport layer, I believe some Microsoft developers will publish the Event Hub implementation sometime in the near future. As for AWS I'm not as proficient there, so maybe someone else can tackle that package.

@Siyfion
Copy link
Contributor

Siyfion commented Jun 21, 2017

@jthegedus Awesome, it almost sounds like a plan taking shape! lol.

As for the AWS-side, I would imagine it's probably the more commonly used cloud provider, so I'm sure there will be some people around that are happy to help, maybe even some of the MDG guys that helped implement the Galaxy hosting solution, I imagine they are pretty familiar with the AWS stack..?

@jthegedus
Copy link

Some resources I've found regarding possible implementations using AWS. These don't use GraphQL, but show how a messaging service can be created on AWS services:

AWS IOT: https://serverless.com/blog/serverless-notifications-on-aws/ @mattfysh
AWS SQS + Cognito: https://serverless.com/blog/how-reuters-replaced-websockets-with-amazon-cognito-and-sqs/ and this https://github.com/ReutersMedia/sqs-browser-events

The interesting thing about a serverless backend is that it changes which problems need solving. Instead of scaling connection etc you need to consider the limitations of the individual services. Eg: payload size, payload TTL, delivery guarantees (at least once and dealing with duplicate deliveries), upstream messaging etc

@jonmanzo
Copy link

jonmanzo commented Aug 2, 2017

I have this working in AWS using the demo from medium. Once I have in incorporated into the project it was poc'd for I'll try and write it up here, but in the meantime: You can't use SNS as it is not a traditional pubsub broker. Have to implement using graphql-mqtt-subscriptions, AWS IOT & the aws iot js sdk

@giautm
Copy link

giautm commented Aug 3, 2017

@jonmanzo : Hi!, can you share the demo link from medium? :p

@jonmanzo
Copy link

jonmanzo commented Aug 3, 2017

@giautm Here you go, but bear in mind it is a little bit out of date due to
the subscriptions-transport-ws spec being in flux

Client: https://dev-blog.apollodata.com/tutorial-graphql-subscriptions-client-side-40e185e4be76
Server: https://dev-blog.apollodata.com/tutorial-graphql-subscriptions-server-side-e51c32dc2951

@gnanda17
Copy link

I just published an initial version of a ws transport client and a server package that works with AWS iot and lambda. AWS IoT is used for socket connections and a db is used to store subscription state.
Server
Client
Example App

@jthegedus
Copy link

jthegedus commented Nov 28, 2017

Just so everyone here is aware, AWS just launched Serverless GraphQL as a Service called AWS AppSync - https://aws.amazon.com/blogs/aws/introducing-amazon-appsync/ and the docs http://docs.aws.amazon.com/appsync/latest/devguide/system-overview-and-architecture.html

This service offers:

  • subscriptions through MQTT but where the servers are managed (I've no idea of the pricing atm)
  • queries, mutations (as expected)
  • support for uploading s3 objects through GraphQL
  • automatically provisioning DynamoDb tables from the GraphQL schema
  • custom resolvers backed by Lambda, DynamoDB and ElasticSearch

They also have a client SDK - https://github.com/awslabs/aws-mobile-appsync-sdk-js - which is built by extending ApolloClient2.0 where offline support, auth and all the network layer are simple apollo-links. Go read the source, it's super cool stuff.

No idea at the moment on whether you can extend the AppSync GraphQL server instances with stuff like ApolloEngine. fingers crossed

@o-alexandrov
Copy link

o-alexandrov commented Dec 13, 2017

@gnanda17 Thank you for posting AWS IoT example.

to everyone:
While it is working, it is definitely extremely expensive:

AWS IoT AWS AppSync 🚀 AWS SNS 🥇
$5 per million 0.5KB updates $2 per million 5KB updates $1 or less per million 64KB updates

It'd be great to see an example of GraphQL subscriptions with AWS SNS or Google Pub/Sub.

@jthegedus
Copy link

@OlzhasAlexandrov When initially looking into this I found that GCP Pub/Sub isn't able to push to device endpoints; at least that was my understanding.

https://cloud.google.com/pubsub/docs/push#configuring-http-endpoints

You need a publicly accessible HTTPS server to handle POST requests in order to receive push messages. The server must present a valid SSL certificate signed by a certificate authority and routable by DNS. You also need to validate that you own the domain (or have equivalent access to the endpoint). Finally, you must register the endpoint domain with the GCP project. Note that these steps are considerably simplified on App Engine, where SSL certificates are provided and verification requirements can be relaxed.

I didn't invest any further time and actually test an implementation to see if this was the case.

I am still working on an FCM based transport, but it's delayed a bit due to changing implementation lang.

@sid88in
Copy link

sid88in commented Jan 1, 2018

@jthegedus @OlzhasAlexandrov very cool insights!

  1. We have integrated appsync mutation and query support so far in https://github.com/serverless/serverless-graphql . Next we are exploring how to implement subscriptions as it comes out of the box with appsync! Backend is serverless (GraphQL Proxy in Appsync).

  2. Any feedback / contributions are welcomed for open issues in https://github.com/serverless/serverless-graphql

  3. Here is some pricing info taken from Adrian's talk on AWS Amplify and AWS Appsync.

screen shot 2017-12-30 at 10 12 26 am

screen shot 2017-12-30 at 10 12 07 am

@grantwwu
Copy link
Contributor

Closing this issue because it is unclear if the topics being discussed are actually in scope for this project.

@lorensr
Copy link

lorensr commented Apr 26, 2019

Related issue in apollo-server repo: apollographql/apollo-server#2129

@boredland
Copy link

I am still working on an FCM based transport, but it's delayed a bit due to changing implementation lang.

hey @jthegedus did you ever make any progress on that? we currently already have fcm in our project for web-push notifications and using the same as a replacement for websockets sound intrigueing.

@jthegedus
Copy link

jthegedus commented May 5, 2020

@boredland I gave up on building an FCM transport for GraphQL.

These are the results of my investigation (though I am certainly incorrect in some places, corrections welcome):

graphql-subscriptions gives us PubSub Engine as a means to configure the transport for inter-server messaging. Not for how we send messages to the client devices.

graphql-subscriptions does not give us access to configure the subscribe storage of a user/query pair (I believe this uses the server's disk storage to track this information). Given this we cannot use FCM to track the user/query subscription data as would be ideal.

The FCM design would also require heavy client-side integration. It would need to capture the FCM data message and perform a merge of the result into the local GraphQL cache. I couldn't figure an easy way that didn't require lock-in to the Apollo ecosystem / include other graphql clients.

Given this library doesn't offer the configuration I would desire, I gave up instead of trying to build my own GraphQL server module.

The ideal design here would be:

  • server: stateless GraphQL
  • server: when a subscription event for a query ocurrs, forward to FCM and add that user to the "topic" (in practice this topic ID would be a value similar to a persisted query ID. IE: query + params hashed)
  • server: when a publish event occurs, trigger an FCM publish event with the resultant payload
  • client: receives FCM data payload, merges this into the local GraphQL client cache

Advantages:

  • stateless GraphQL APIs on ephemeral compute can scale without any management overhead
  • FCM is free and completely managed
  • websocket free client and server remove an endless set of issues
  • single way data flow

Disadvantages:

Other notes:


For my recent thoughts on GraphQL subscriptions, see this thread on the request to add subscriptions to the popular graphql-react project.

Having said that though, if GraphQL subs over FCM existed I would use it in a heartbeat over websockets or polling.

@boredland I'm happy to collaborate/contribute should you go down this path. I think I gave up to soon and now am not heavily involved in GraphQL daily.

@onhate
Copy link

onhate commented Nov 10, 2020

folks, I’m releasing a serverless specialised graphql framework with support for subscriptions on AWS (later GCP and Azure)

https://github.com/kraken-js/kraken-js

we developed this framework internally and it runs in production already and now we are open sourcing it, it’s still pending documentation and samples to facilitate the life of newcomers but while that is not available feel free to reach out to me if you want to use it and have questions, any feedback is welcome.

@johnnyoshika
Copy link

Has anyone tried using a 3rd party service like Pusher or Pubnub to manage the websocket connection for GraphQL subscriptions? For example, use a short lived HTTP connection like AWS Lambda for queries and mutations, but a different service like Pusher (which uses Redis behind the scenes, I believe) for long lived web sockets connections that pushes the subscriptions out to clients?

@jthegedus
Copy link

@johnnyoshika I looked into Pusher but it has the same issues as FCM does that I outline above. From the existing GraphQL subscription libraries I am aware of, you are only given an interface for configuring message propagation between the servers that front the API, the server-client connection is always considered websockets and the server environment (for subscriptions) is always considered stateful.

@johnnyoshika
Copy link

@jthegedus That makes sense. So far the only service that I found to support Subscriptions (via websockets) out-of-the-box is Heroku. Even then, Heroku's web socket connection times out every 55 seconds (https://devcenter.heroku.com/articles/websockets#timeouts). Apollo Client is pretty good about re-establishing the connection right away, so that doesn't seem to be a problem.

@Ugbot
Copy link

Ugbot commented Feb 4, 2021

@jthegedus / @johnnyoshika Have you tried Ably? We've got an NPM module for GraphQL (https://www.npmjs.com/package/graphql-ably-pubsub) and do all of the reconnection magic you could want.
If its missing key features please tag me and I'll add it to the development list :)

@AlaaZorkane
Copy link

@jthegedus / @johnnyoshika Have you tried Ably? We've got an NPM module for GraphQL (https://www.npmjs.com/package/graphql-ably-pubsub) and do all of the reconnection magic you could want.
If its missing key features please tag me and I'll add it to the development list :)

Hey @Ugbot you guys should definitely add it here: https://github.com/apollographql/graphql-subscriptions#pubsub-implementations to help with discoverability ;)

@Ugbot
Copy link

Ugbot commented Feb 4, 2021

We are trying but they are not accepting the PR 🙁
#237

@johnnyoshika
Copy link

johnnyoshika commented Feb 8, 2021

@Ugbot It looks really good. So can we continue to use AWS (e..g AWS Lambda) for our GraphQL queries and mutations, but then point the client (e.g. Apollo Client) to Aply for just GraphQL subscriptions?

For example, I'd be doing something like this with Apollo Client:

const httpLink = createHttpLink({
  uri: `https://some-aws-url.com/graphql`,
});

const wsLink = new WebSocketLink({
  uri: `wss://some-aply-url.com/endpoint`,
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests