Comments (14)
Hey Brian! Thanks for the question. You’re right it would be good to be more specific, and indeed I know more now and have gone through some design iterations since I wrote that warning a few weeks ago. It’s definitely closer to a “I think it's OK but want people to test” warning than a crazy experiment warning. @ssbb is starting to integrate it into his production application and so far he says it’s looking good! And the happy path appears to be working great!
My biggest concern is that there seem to be some major issues with the Elm websockets package. There are several stale github issues in that package, and any core issues there prevent any Elm code using websockets from being 100% stable. In particular, the issue I have observed is that if there’s an issue with the server connection the websockets package will try to create a new connection every second or so, but as far as the consumer is concerned (in this case Graphqelm), the connection is still healthy. Unfortunately I lost the slack history for the relevant discussion, @ssbb had some thoughts on this and noted some relevant issues on Github (and that https://github.com/fbonetti/elm-phoenix-socket/issues had encountered some similar problems). I slacked him about it in #graphql and I’ll reply here when I get that context back.
I would love to get some help in general in understanding these issues around corner cases, both from people willing to test it and from anyone with knowledge about the Elm WebSockets package. It would be awesome to compile a really solid list of how to reproduce these issues, and which WebSockets issues they stem from (or what possible workarounds Graphqelm could use if possible). I don’t think there’s a ton more I can do to add stability at this point without some fixes to the WebSockets package, but compiling that information and documenting it thoroughly would at the very least allow me to be more specific in warning users, and would allow me to request fixes to the WebSockets package based on these concrete issues.
Besides that major concern, here is the status of Subscriptions in Graphqelm:
Looking Good
- Happy Path (initialize a connection, listen for incoming messages for the subscription, decode them correctly)
- Basic API design - several people have slacked me and said they are integrating Graphqelm subscriptions into their apps. I’ve gotten lots of positive feedback, and some suggestions which I’ve already integrated. All in all it appears to be solid and should be reasonably stable.
- Framework support - I’ve created
Graphqelm.Subscription.Protocols
for the Rails GraphQL implementation and for Elixir/Absinthe/Phoenix, and they have both been tested and confirmed working for the happy path.
Known Missing
- Queuing mutation requests If the connection is lost, any mutations you send over the WebSocket will not be queued (you can still send them over Http, though, and this works perfectly). The Elm websocket connection handles retries correctly (I believe), but they are succesful as far as the request’s response code goes, it’s just that the connection to the subscription was lost so it will fail to send them. This should probably be queued up and resent upon reconnection at the Graphqelm layer since Elm can’t be aware of that issue.
- Other frameworks’ Protocols I’m not sure if the Protocol abstraction will work for other frameworks or not (like the NodeJS one, for example). It may need to evolve in a non-trivial way if there are any major differences in other server’s Subscription protocols. However, I’m not too concerend about this because Elm makes it fairly safe to adapt to API changes, and hopefully most users won’t even notice.
- Detecting lost Subscription Can I discover based on the server’s response whether the Subscription connection was lost and needs to be re-established? I need to investigate this more in-depth and see what I can do here.
- Better Subscription event hooks There are some things missing or requiring more polish in terms of registering messages for when an error occurs, when the connection fails, etc.
I’ll work on improving the warning in the docs to be more concrete once I’m back from my trip in a week or so. Thanks again for starting the discussion!
from elm-graphql.
Great, thank you! I have same function already (it's just an JSON decoder at all). Since I am decoding raw subscription data I just using Json.Decode.at
:
subscriptionDecoder : SelectionSet decodesTo typeLock -> JD.Decoder decodesTo
subscriptionDecoder (SelectionSet fields decoder) =
JD.at [ "result", "data" ] decoder
I have a deadline right now, but will able to create an example of integrating with elm-phoenix later (need to fix my PR also). Anyway after some work on it I can say it's a good idea to abstract subscriptions and should be easy to create packages for integration.
from elm-graphql.
wow! Thank you for the very detailed answer. I'll give it a shot, then. 😄
from elm-graphql.
Dillon, thanks for the detailed writeup. I have been giving some thought lately to whether all this should be built into this project. It seems to me that this project could remain focused on being the source for autogeneration of elm types from a graphql schema. If you think of it that way, your goal for subscriptions would then be to provide a standard set of event / hooks for third-party socket libraries to adapt to. https://github.com/fbonetti/elm-phoenix-socket is a nice one for phoenix and no doubt there are other quality projects. An adapter would be written for each third-party lib to integrate with this project. While I am confident you could write your own support, getting this right is not that easy. The socket needs to reconnect, then the channels, then the subscriptions and it all needs to be resilient to a connection that may be flapping. If you structured things right you could always write your own socket support in parallel, as a sibling project. On the other hand, if socket support remains an integral part of this project, you have fine-grained control but you take on an expanding set of issues that seem adjacent to your core mission.
from elm-graphql.
@akeating thanks for the thoughtful response, I really appreciate your thought process here. @ssbb just reported back to me on his experiments in using Graphqelm Subscriptions in his app, and he told me he ran into some issues with the channel reconnect logic that I mentioned above. He just expressed a similar opinion that he thinks that Graphqelm should let framework-specific packages handle the Subscription transport layer, and Graphqelm should only handle building GraphQL documents and decoding responses.
Here are some points he brought up:
- Phoenix Presence API - If he used Graphqelm for the end-to-end GraphQL subscriptions, then he’d need to use a different package and a different WebSocket connection for Presence (an Elixir/Phoenix construct for seeing when users log on/off, like seeing who’s online in a chat client for example). That’s something that is clearly outside of the scope of Graphqelm, so that’s a pretty good argument for decoupling them.
- Other transport protocols - It’s completely possible according to the GraphQL spec to do subscriptions over HTTP polling, for example, or other transport protocols besides WebSockets. This would also definitely be outside of the scope of Graphqelm.
Given all the considerations above I think it makes sense to do as both of you suggest @akeating and @ssbb and to decouple the transport knowledge from Graphqelm. It would be awesome to make this seamless and foolproof so that “if it compiles it works”. We’ll have to play around with the API both on the Graphqelm-end and in the framework specific libraries (I’ll likely make some pull requests and ask for help from people who are experimenting to develop some nice APIs).
It’s super helpful to get concrete code snippets on how this is happening, so keep the feedback coming! Thanks all for this great discussion!
For reference, here is how @ssbb is setting up the GraphQL Subscription using https://github.com/saschatimme/elm-phoenix:
subscriptionPayload =
JE.object
[ ( "query", Graphqelm.Document.serializeSubscription subscriptionDocument |> JE.string )
]
subscriptionMessage =
Push.init "__absinthe__:control" "doc"
|> Push.withPayload subscriptionPayload
And then Phoenix.push taco.websocketUrl subscriptionMessage
as cmd.
from elm-graphql.
@ssbb I made the GraphQL response decoders public (see Graphqelm.Document.decoder
). Could you try using that for your example using the Elm Phoenix package and let me know how it works for you? @akeating if you'd like to try that as well (or anybody else!), that would be extremely helpful.
Then based on your feedback I will figure out the next steps for a migration path to move Subscriptions to outside packages.
I'm thinking it will look something like:
Documentation
- Give general info about how to setup Subscriptions
- Link to known packages that support setting up Graphqelm Subscriptions
- Add example in
examples
folder using one of the Phoenix packages
3rd Party Packages
- Might need to make some pull requests for the Elm/Phoenix packages to make it easier or more robust to setup Graphqelm Subscriptions
- Does anything exist already that would allow you to do this with Rails or other frameworks? Perhaps for now a message to invite others to contribute these would be a good start.
Remove deprecated
- Give a warning that the
Graphqelm.Subscription
is deprecated and going to be removed - Remove it (after a month or so maybe)
from elm-graphql.
@dillonkearns How has this matured? We are looking at starting to use subscriptions now, and Graphqelm has been fantastic for us so far!
from elm-graphql.
Hey @anagrius, I'm glad to hear Graphqelm been a good experience for you and your team!
The status is that I'm looking to remove the built-in Subscription functionality as discussed here, but I'll need help from users who are experimenting with Subscriptions, such as @ssbb and perhaps you and your team, to make the transition.
It's definitely a safe bet to go ahead and use Graphqelm
to build up your queries in conjunction with elm-phoneix
(or another Elm subscription package) to deal with the low-level channel connection logic. This is exactly what @ssbb is doing right now. With this approach, you're not coupled to anything in Graphqelm
that will change so there won't be anything for you to change when I remove the subscriptions code. And you could really help me push this forward by reporting back on how that goes! I'd love to hear feedback at any point, either here or on Slack!
from elm-graphql.
I've gone ahead and officially removed the Graphql.Subscription
module from this package. You should still be able to get the Subscription GraphQL query and decoder with the Graphql.Document.serializeSubscription
and Graphql.Document.decoder
functions.
I would love to hear feedback about this! If you are integrating GraphQL subscriptions using dillonkearns/elm-graphql
, please extract some code snippets from your actual examples as a basis for conversation. You can either open up a new Github issue, or ping me on the Elm Slack. Thanks everyone for the great discussion here!
Thanks everyone who chimed in on this topic, and thanks Richard for opening the issue!
See the changelog for more details.
from elm-graphql.
Any chance of updating the old example to show how the new package can be used with a manual/externally supplied connection?
from elm-graphql.
Hello @JonRowe, thank you for the suggestion! That's a great idea. I created this issue to track making an Ellie example using the new approach. There are some reasons it might make sense to hold off on this (I captured them in #70). Here are the notes I wrote there for reference:
Now that the transport layer code has moved out of
dillonkearns/elm-graphql
based on #43, we should have an Ellie example linked to in the README to illustrate how this could be done (as this comment points out).This may have to wait until the elm/websocket package, and perhaps a package for Elm and Phoenix, are published. This package uses long polling with Phoenix as a workaround, but is listed as not being production ready yet so it might be best to hold off for now.
from elm-graphql.
@dillonkearns I have just started using this package with an Elixir/Absinthe backend. I like it so far and appreciate your work very much!
Do you have any suggestions on how GQL subscriptions can be handled until an elm/websocket package comes along?
from elm-graphql.
Hello @MonadicT, I'm glad you're enjoying the library!
It's actually not that different to use the Elm websockets package compared to going out to a port. In fact, in some ways it's simpler because you can use Phoenix's javascript code for connecting to channels: https://hexdocs.pm/phoenix/js/
All you have to do is wrap some ports that use that library on the JS side, and send a message over to Elm every time new data comes in. You'll need a "Cmd port" (Elm to JS) to send the query over to tell JavaScript to start the subscription. Then you can listen for a Json.Decode.Value
through a Sub port
(JS to Elm) for every time data comes in.
If you need more details, ask on the #graphql channel in the Elm Slack: https://elmlang.herokuapp.com/. There are lots of friendly people there who can give you a quick answer to your question!
from elm-graphql.
@dillonkearns Thanks for your quick response! Guess I will just use ports. Thanks for the JS code pointer.
from elm-graphql.
Related Issues (20)
- Enhancement - Add support for Dgraph HOT 1
- non null list of non null list of… HOT 6
- Include an exhaustive query for each type HOT 3
- elm-graphql generation fails if there are no columns selected (Hasura) HOT 6
- Add operationName to mutation request body HOT 1
- Enum with underscore as a leading character, changed after generating elm code. HOT 1
- Scalar decoder fails when the field contains an object. HOT 1
- Scalars should not be encoded as json in mutations HOT 3
- Enforce nonempty list in required list arguments HOT 3
- Selecting implementation attributes from interfaces HOT 2
- Corrupt package data for 5.0.5? HOT 1
- Requesting feedback on the following changes to the serializeChildren function regarding field hashing HOT 2
- Can not find ScalarCodecs HOT 1
- Feature request: Convenience functions for primitive comparisons HOT 3
- Idea: serialize invalid JSON Input Values as arguments
- Missing fragment in Interface `Fragments` type HOT 1
- Idea: include deprecation warnings into the generated code as comments HOT 1
- Building large queries takes a long time and pauses the UI HOT 2
- Encode function for enums is missing HOT 1
- Generate input object helpers HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from elm-graphql.