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

Support subscriptions #203

Merged
merged 4 commits into from
Oct 22, 2018

Conversation

matiasanaya
Copy link
Contributor

@matiasanaya matiasanaya commented May 5, 2018

This addresses the subscription part of #15.

Please look through subscription_test.go which has an example subscription resolver implemented.

I've left // TODO: ... markers where I feel the implementation could be improved, though not sure how.

Missing from this PR is tracing for the execution of each query.

I've put together a graphQL server that supports subscriptions as a proof of concept based on these changes (though it might be out of sync since this PR is changing)

// Send response within timeout
// TODO: maybe block until sent?
select {
case <-subCtx.Done():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you send a timeout error here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't believe it would make sense to try and send a timeout error since we've time'd out waiting to send an actual response. But I do think maybe this should be checking against ctx.Done() instead. Thoughts?

import (
"context"
"encoding/json"
stdErrors "errors"
Copy link
Member

@pavelnikolov pavelnikolov May 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd personally add an alias to the other "errors" package and leave the standard lib one as is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

helloSaid {
msg
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, fix indentation above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return r.msg, r.err
}

func closedUpstream(rr ...*helloSaidEventResolver) <-chan *helloSaidEventResolver {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be named closedChannel instead? For a moment, I got confused about the meaning of upstream here.

subscription onHelloSaid {
helloSaid {
msg
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

subscription onHelloSaid {
helloSaid {
msg
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


type Query {
hello: String!
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

const schema = `
schema {
subscription: Subscription,
query: Query
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@pavelnikolov
Copy link
Member

This is a good start! Thank you @matiasanaya!
I know it is outside of the scope of this PR, but it would be really nice to add a subscription to the StarWars example!

@pavelnikolov
Copy link
Member

lgtm

@matiasanaya matiasanaya force-pushed the feature/subscriptions branch from 08079d8 to a2b77e9 Compare May 11, 2018 21:09
@ghost
Copy link

ghost commented May 22, 2018

Hello everyone who are pursuing the endeavor of implementing subscriptions. How it is going recently? Do you need assistance?

@tsauvajon
Copy link

We strongly need subscriptions aswell, we would be glad to help if any work remains before merging this PR!

@matiasanaya
Copy link
Contributor Author

@Xeizzen @tsauvajon - I've written a new transport library that aligns with this library and updated the subscription example server with a more robust implementation. If you are keen, please have a look at those projects, try them out and contribute :)

@tsauvajon
Copy link

tsauvajon commented Jun 13, 2018

LGTM, I tried it in our project and it works as planned.
I've used you "say hello" exemple only at the moment (poudre-aux-yeux/rapiquette@271f9c7), but I will share when I go further.

EDIT: we implemented some features with this and it's perfect for our needs. Subscriptions work as planned. We love the use of channels for this.

@tsauvajon
Copy link

The thing I don't really understand is

select {
  case r.pointScoredEvents <- e:
  case <-time.After(1 * time.Second):
}

Why use a select, and why this time.After ?

@pavelnikolov
Copy link
Member

pavelnikolov commented Jun 14, 2018

The above select statement will block until one of these happen:

  1. either a message is received from the r.pointScoredEvents channel (if there is no buffer or buffer capacity); or
  2. the operation times out after 1 second

In other words - wait for someone to receive your message (i.e. e), but don't wait for more than 1 second.

@ande8133
Copy link

We also really need subscriptions. I was wondering how close this is to being checked in. =)

@tsauvajon
Copy link

tsauvajon commented Jun 18, 2018

@ande8133 check @matiasanaya 's link. Subscriptions work for me following his example. I just had to add CORS and return 200 on OPTIONS (for preflight requests).

Copy link

@kivutar kivutar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got it working using this PR too. We should definitely merge this. It's a very good starting point.

@stephenafamo
Copy link

Is there a reason why this is not yet merged?
Is any help needed?
Everything seems to work fine.

@pavelnikolov
Copy link
Member

I was wondering the same...

@bsr203
Copy link

bsr203 commented Sep 22, 2018

@tonyghita @neelance please consider spending little of your time as it been the most requested feature and many claim works well. thank you.

@smithaitufe
Copy link

IMHO, It seems PRs are not appreciated.

@bsr203
Copy link

bsr203 commented Sep 22, 2018

@smithaitufe @neelance commented here as he don't have the bandwidth for some time. I wish more capable maintainers are identified :-( .

@stephenafamo
Copy link

Is there no one else maintaining this project? Is it just @neelance ?

@neelance
Copy link
Collaborator

I am not maintaining this project any more, since I'm currently (unfortunately) not working on any project that uses GraphQL. Therefore I'm a bit detached from the GraphQL ecosystem atm and someone else would probably do a better job at maintaining this project. @tonyghita already volunteered, but we can add another helping hand if someone wants to take the job. ;-)

@pavelnikolov
Copy link
Member

I would like to volunteer. I have been following the project very carefully and my team has been using it in production for more than 1.5 years. We are interested in subscriptions but also extensions and other GraphQL features. @matiasanaya (the author of this PR) is also from my team and I peer-tested his work long time ago. I'm a little disappointed that there hasn't been much activity lately.
If you accept contributors/maintainers I'd be happy to participate/help.

@stephenafamo
Copy link

I'll be happy to, although since I've not contributed to this project before, I don't know if I am the best person to do it.

However, I am working heavily with something involving GraphQL, and will be for a while.

@pavelnikolov
Copy link
Member

Adding this project to the #gfrs list in the gophers Slack might be a good idea. This way it can be trully community managed!
IMHO, This project is awesome! The only problem is that it is not maintained regularly. And there isn't much interaction with potential contributors/volunteers.

@stephenafamo
Copy link

I agree @pavelnikolov

@neelance
Copy link
Collaborator

I'd like to have a single primary maintainer for the project. The primary maintainer can add secondary maintainers if desired.

@pavelnikolov Using it for 1.5 years sounds like a good qualification. :)

@tonyghita Would it be okay with you to make @pavelnikolov the primary maintainer?

@stephenafamo
Copy link

I think this would be great.

@adriancuadros
Copy link

Awesome Library kudos and thanks to the new maintainers @pavelnikolov and @tonyghita

@pavelnikolov
Copy link
Member

pavelnikolov commented Sep 26, 2018

Thank you for trusting in me! It is an awesome privilege and I will take this responsibility seriously.
I’m going on a quick holiday and when I’m back next Tuesday subscriptions will be my first priority.
@matiasanaya let’s catch up early next week re subscriptions, ws transport and example(s).

@romshark
Copy link

As I read about websocket transport I'd like to ask this question: will the library remain transport-layer agnostic? Will we be able to use graphql-go with subscriptions support on top of any custom transport layer?

I'm worried because we're using a home-grown websocket abstraction library called webwire together with graph-gophers/graphql-go and we currently implemented subscriptions without GraphQL support just by using webwire server-side signals and regular mutations

@pavelnikolov
Copy link
Member

@romshark I think that the library has to remain transport agnostic and as minimalistic as possible! The WS transport will be added as a separate repository under graph-gophers.

@lindroth
Copy link

lindroth commented Oct 15, 2018

@matiasanaya does this use one websocket for all the subscriptions that the client has, or is it multiple connections?

I know that with apollo it's possbile to send queries and mutations via websocket as well.

@pavelnikolov
Copy link
Member

@lindroth the library itself is transport agnostic. The subscriptions updates are sent over Go channel. It's up to the user of the library to decide how to handle it. There is a reference websocket implementation that @matiasanaya worked on and send a PR graph-gophers/graphql-transport-ws#1
I'm reviewing both PRs now.

@matiasanaya
Copy link
Contributor Author

@lindroth if you end up using graph-gophers/graphql-transport-ws (once it's merged), one websocket can be used to handle all subscriptions, queries and mutations. It's based on the apollo implementation. In the end though it's going to be up to the client you use.

@pavelnikolov pavelnikolov merged commit b174f9e into graph-gophers:master Oct 22, 2018
@tsauvajon
Copy link

🎉

@hampusohlsson
Copy link

Awesome work on this!

one websocket can be used to handle all subscriptions, queries and mutations

@matiasanaya Trying to do exactly what you're suggesting here - use websockets for not just subscriptions but querying as well (to lower the number of http requests from the browser), but the implementation seems to explicitly prevent that.

if op.Type != query.Subscription {
return sendAndReturnClosed(&Response{Errors: []*qerrors.QueryError{qerrors.Errorf("%s: %s", "subscription unavailable for operation of type", op.Type)}})
}

I'm using apollo-link-ws on the browser side. Am I missing something?

@pavelnikolov
Copy link
Member

@hampusohlsson Thanks for your comment. I haven't used apollo-link-ws but maybe it's worth raising a separate issue.

@matiasanaya
Copy link
Contributor Author

@hampusohlsson I believe you are right and that I've, at some point, sneaked in this limitation. Care to raise a separate issue so we can track the work to support queries and mutations through subscriptions?

@hampusohlsson
Copy link

No problem! Opened an issue here #286

tinnywang pushed a commit to tinnywang/graphql-go that referenced this pull request Dec 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.