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

Add subscriptions #82

Merged
merged 17 commits into from
Dec 4, 2019
Merged

Add subscriptions #82

merged 17 commits into from
Dec 4, 2019

Conversation

kinow
Copy link
Member

@kinow kinow commented Sep 26, 2019

Closes #14

  • Will use a file that is still under review, but we have tested and it works for what we need (and looks like the code review will take much longer in graphql-ws)
  • Will use the simplest approach available, of just looping and asyncio.sleeping for a few seconds, then sending more data. This can be improved later to send data only when there is data available, but this will be an improvement for later.

Sibling PRs:

@kinow kinow added this to the 0.2 milestone Sep 26, 2019
@kinow kinow self-assigned this Sep 26, 2019
@kinow
Copy link
Member Author

kinow commented Sep 26, 2019

Work in progress, will start adding now the code to have subscriptions. But this was what was more obvious to me that was necessary for this change. More to come in the next days 👍

@codecov-io
Copy link

codecov-io commented Sep 26, 2019

Codecov Report

Merging #82 into master will increase coverage by 3.64%.
The diff coverage is 97.22%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #82      +/-   ##
==========================================
+ Coverage   48.81%   52.45%   +3.64%     
==========================================
  Files           6        6              
  Lines         338      366      +28     
  Branches       57       57              
==========================================
+ Hits          165      192      +27     
- Misses        170      171       +1     
  Partials        3        3
Impacted Files Coverage Δ
cylc/uiserver/main.py 66.66% <100%> (+0.59%) ⬆️
cylc/uiserver/handlers.py 79.26% <96.66%> (+8.35%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ed4574b...86fc8a8. Read the comment docs.

@kinow kinow force-pushed the add-subscriptions branch 4 times, most recently from a5a89df to bdef1dc Compare September 26, 2019 02:22
@dwsutherland
Copy link
Member

dwsutherland commented Sep 26, 2019

I think we can add the UIS Subscriptions machinery (modules, endpoints ...etc) to this PR (like you have), but develop the GraphQL schema in cylc-flow..
(even for the simplest case because we can just test/dev locally with cylc-uiserver & cylc-flow)

This way we design it, from the beginning, to be able to plug into either WS or UIS subscription resolvers...

@kinow
Copy link
Member Author

kinow commented Sep 26, 2019

Oh that's helpful. I saw you define resolvers in cylc flow, then extend it here and add only the specific for uiserver. Clever.

So this ia pretty much it for uiserver for now? We leave it like this and now start working on chema changes in cylc flow??

@dwsutherland
Copy link
Member

cylc-flow might need allow_subscriptions sorted in the handler.

@dwsutherland
Copy link
Member

Oh that's helpful. I saw you define resolvers in cylc flow, then extend it here and add only the specific for uiserver. Clever.

So this ia pretty much it for uiserver for now? We leave it like this and now start working on chema changes in cylc flow??

I think so, once you have this one working locally with the simple case in cylc-flow (and GraphiQL working).

cylc/uiserver/main.py Outdated Show resolved Hide resolved
@matthewrmshin matthewrmshin mentioned this pull request Sep 26, 2019
@kinow
Copy link
Member Author

kinow commented Sep 26, 2019

@dwsutherland I've added the template to render websocket subscriptions in GraphiQL.

Moved everything websockets related under the cylc.uiserver.websockets. This package is temporary, excluded in pycodestyle, and should either disappear or be simplified once we have the PR merged (could have called it subscriptions, but not good naming things :).

The UI is still working, tested with a running workflow. Then going to /user/kinow/subscriptions I get the normal message that an HTTP GET is not able to talk WebSockets. And submitting a query like

subscription {
  workflows {
    id
  }
}

I can see that the message was submitted to the backend, parsed, interpreted, and rejected because the schema is not ready to handle it yet.

image

I think we are done here for now. And now the only missing parts are in the cylc-flow repository. What do you think @dwsutherland ?

@dwsutherland
Copy link
Member

I think we are done here for now. And now the only missing parts are in the cylc-flow repository. What do you think @dwsutherland ?

Yes, although perhaps we could leave this one open until we have put a minimal Subscription into cylc-flow?

@kinow
Copy link
Member Author

kinow commented Sep 26, 2019

I think we are done here for now. And now the only missing parts are in the cylc-flow repository. What do you think @dwsutherland ?

Yes, although perhaps we could leave this one open until we have put a minimal Subscription into cylc-flow?

Yup, I'm planning to mark it ready for review once we get at least one subscription working, so that we can test it from point (ui + hub) to point (cylc-flow with running workflow data).

Copy link
Member Author

@kinow kinow left a comment

Choose a reason for hiding this comment

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

@dwsutherland this one won't change much for now. I've added some comments to the code to help reviewers 👍

@@ -24,7 +24,7 @@ python: 3.7

before_install:
- pip install pycodestyle
- pycodestyle --exclude=".git,.tox,__pycache,venv,.eggs,build,jupyterhub_config.py"
- pycodestyle --exclude=".git,.tox,__pycache,venv,.eggs,build,jupyterhub_config.py,cylc/uiserver/websockets/"
Copy link
Member Author

Choose a reason for hiding this comment

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

This is due to the graphene-tornado class that we copied from an open PR. Mainly due to line number that is greater than 80 there 👍 so we need to ignore that for now.

@@ -145,9 +150,58 @@ def prepare(self):
super().prepare()


class SubscriptionHandler(websocket.WebSocketHandler):
Copy link
Member Author

Choose a reason for hiding this comment

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

Note: copied from the PR's example.

cylc/uiserver/handlers.py Show resolved Hide resolved
return wider_context


class GraphiQLHandler(UIServerGraphQLHandler):
Copy link
Member Author

Choose a reason for hiding this comment

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

From the PR's example. This handler renders a custom React app that talks WebSockets. So that the query is reloaded automatically 👍

from string import Template


def render_graphiql(base_url: str) -> str:
Copy link
Member Author

Choose a reason for hiding this comment

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

From the PR's example.

Copy link
Member Author

Choose a reason for hiding this comment

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

Modified to create the WebSocket subscription URL using JS for hostname and port, and Python for the base URL.

setup_observable_extension()


class TornadoConnectionContext(BaseConnectionContext):
Copy link
Member Author

Choose a reason for hiding this comment

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

From the PR's example, with one modification.

cylc/uiserver/websockets/tornado.py Show resolved Hide resolved
cylc/uiserver/handlers.py Show resolved Hide resolved
@kinow kinow marked this pull request as ready for review September 30, 2019 22:34
@kinow kinow mentioned this pull request Sep 30, 2019
6 tasks
@kinow
Copy link
Member Author

kinow commented Oct 3, 2019

Added some unit tests. Should be ready for review now.

@kinow
Copy link
Member Author

kinow commented Oct 9, 2019

Juts added a new commit with the changelog.

Copy link
Member

@dwsutherland dwsutherland left a comment

Choose a reason for hiding this comment

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

LGTM 👍 .. Worked locally ( I don't think this breaks existing functionality )

@kinow
Copy link
Member Author

kinow commented Oct 17, 2019

Oh, got one conflict in the handlers, will fix it in a few minutes 👍

@kinow
Copy link
Member Author

kinow commented Oct 20, 2019

I think I found one possible solution. A mix of more JS, and just a little Python. We still replace the base_url (required as we need to know what value goes in /user/$USER/), but the protocol+host+port can be done in JS.

The WebSocket client is created on the client-side, so it should be safe to ignore JupyterHub configurations like c.JupyterHub.port and ...host, and just grab whatever is specified in the browser.

Test with default port 8000 after running jupyterhub.

image

Then the result after running jupyterhub --ip=10.0.2.15 --port=4444:

image

@kinow
Copy link
Member Author

kinow commented Dec 3, 2019

Rebased and conflicts fixed.

Copy link
Member

@hjoliver hjoliver left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@hjoliver hjoliver merged commit 23473ad into cylc:master Dec 4, 2019
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.

Add GraphQL subscriptions support via WebSocket
4 participants