-
Notifications
You must be signed in to change notification settings - Fork 428
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
GraphQL subscriptions for stanzas #3830
Conversation
e1ee88a
to
e94c529
Compare
This comment was marked as outdated.
This comment was marked as outdated.
90959bd
to
6a8e282
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
6a8e282
to
7b1d29f
Compare
This comment was marked as outdated.
This comment was marked as outdated.
Codecov ReportBase: 83.04% // Head: 83.10% // Increases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #3830 +/- ##
==========================================
+ Coverage 83.04% 83.10% +0.05%
==========================================
Files 528 534 +6
Lines 33926 34020 +94
==========================================
+ Hits 28174 28271 +97
+ Misses 5752 5749 -3
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
7b1d29f
to
aa70e45
Compare
This comment was marked as outdated.
This comment was marked as outdated.
aa70e45
to
f01acdd
Compare
This comment was marked as outdated.
This comment was marked as outdated.
f01acdd
to
199e75e
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
453435f
to
68c9ff2
Compare
This comment was marked as outdated.
This comment was marked as outdated.
68c9ff2
to
823f2a0
Compare
This comment was marked as outdated.
This comment was marked as outdated.
- Subscriptions can be executed only with SSE. - Queries and mutations can be executed with HTTP or CLI.
This makes it possible to the execute a prepared subscription operation upon receiving each event. Also: make it possible to return 'aux' data.
823f2a0
to
19d8b2a
Compare
This comment was marked as outdated.
This comment was marked as outdated.
It uses lasse, just like the REST SSE handler
- Handle SSE requests under the '/sse' subpath - Export utils used by the SSE handler - Allow passing parameters with GET (qs) or POST (body). This follows the GraphQL specs, and allows to handle SSE.
- unsupported operation - invalid query string
This common code is used by REST and GraphQL SSE handlers.
This is actually used only for building the queries for tests. The commands will be displayed in the CLI help - we can change this later if needed.
19d8b2a
to
1c79706
Compare
This comment was marked as outdated.
This comment was marked as outdated.
Put the more generic tests (mostly error handling) in a separate suite.
1c79706
to
856b379
Compare
small_tests_24 / small_tests / 856b379 small_tests_25 / small_tests / 856b379 ldap_mnesia_24 / ldap_mnesia / 856b379 dynamic_domains_pgsql_mnesia_24 / pgsql_mnesia / 856b379 dynamic_domains_mysql_redis_25 / mysql_redis / 856b379 ldap_mnesia_25 / ldap_mnesia / 856b379 dynamic_domains_pgsql_mnesia_25 / pgsql_mnesia / 856b379 graphql_last_SUITE:admin_cli:admin_last_configured:admin_last:admin_count_active_users{error,{{assertEqual,[{module,graphql_last_SUITE},
{line,284},
{expression,"get_ok_value ( p ( countActiveUsers ) , Res )"},
{expected,2},
{value,1}]},
[{graphql_last_SUITE,admin_count_active_users_story,3,
[{file,"/home/circleci/project/big_tests/tests/graphql_last_SUITE.erl"},
{line,284}]},
{escalus_story,story,4,
[{file,"/home/circleci/project/big_tests/_build/default/lib/escalus/src/escalus_story.erl"},
{line,72}]},
{test_server,ts_tc,3,[{file,"test_server.erl"},{line,1782}]},
{test_server,run_test_case_eval1,6,
[{file,"test_server.erl"},{line,1291}]},
{test_server,run_test_case_eval,9,
[{file,"test_server.erl"},{line,1223}]}]}} dynamic_domains_mssql_mnesia_25 / odbc_mssql_mnesia / 856b379 elasticsearch_and_cassandra_25 / elasticsearch_and_cassandra_mnesia / 856b379 internal_mnesia_25 / internal_mnesia / 856b379 pgsql_mnesia_24 / pgsql_mnesia / 856b379 pgsql_mnesia_25 / pgsql_mnesia / 856b379 mysql_redis_25 / mysql_redis / 856b379 mssql_mnesia_25 / odbc_mssql_mnesia / 856b379 riak_mnesia_24 / riak_mnesia / 856b379 dynamic_domains_pgsql_mnesia_25 / pgsql_mnesia / 856b379 |
small_tests_24 / small_tests / 0407461 small_tests_25 / small_tests / 0407461 dynamic_domains_pgsql_mnesia_24 / pgsql_mnesia / 0407461 ldap_mnesia_24 / ldap_mnesia / 0407461 dynamic_domains_pgsql_mnesia_25 / pgsql_mnesia / 0407461 ldap_mnesia_25 / ldap_mnesia / 0407461 dynamic_domains_mysql_redis_25 / mysql_redis / 0407461 pgsql_mnesia_24 / pgsql_mnesia / 0407461 elasticsearch_and_cassandra_25 / elasticsearch_and_cassandra_mnesia / 0407461 riak_mnesia_24 / riak_mnesia / 0407461 mysql_redis_25 / mysql_redis / 0407461 pgsql_mnesia_25 / pgsql_mnesia / 0407461 mssql_mnesia_25 / odbc_mssql_mnesia / 0407461 dynamic_domains_mssql_mnesia_25 / odbc_mssql_mnesia / 0407461 bosh_SUITE:essential:accept_higher_hold_value{error,
{{assertEqual,
[{module,bosh_SUITE},
{line,251},
{expression,"get_bosh_sessions ( )"},
{expected,[]},
{value,
[{bosh_session,<<"67f4451b903a90e3f84952c5e890345be82bf311">>,
<9147.5996.0>}]}]},
[{bosh_SUITE,accept_higher_hold_value,1,
[{file,"/home/circleci/project/big_tests/tests/bosh_SUITE.erl"},
{line,251}]},
{test_server,ts_tc,3,[{file,"test_server.erl"},{line,1782}]},
{test_server,run_test_case_eval1,6,
[{file,"test_server.erl"},{line,1291}]},
{test_server,run_test_case_eval,9,
[{file,"test_server.erl"},{line,1223}]}]}} dynamic_domains_mssql_mnesia_25 / odbc_mssql_mnesia / 0407461 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, minor typos in docs
0407461
to
95cfce5
Compare
small_tests_24 / small_tests / 95cfce5 small_tests_25 / small_tests / 95cfce5 ldap_mnesia_24 / ldap_mnesia / 95cfce5 dynamic_domains_pgsql_mnesia_24 / pgsql_mnesia / 95cfce5 dynamic_domains_pgsql_mnesia_25 / pgsql_mnesia / 95cfce5 dynamic_domains_mysql_redis_25 / mysql_redis / 95cfce5 ldap_mnesia_25 / ldap_mnesia / 95cfce5 pgsql_mnesia_24 / pgsql_mnesia / 95cfce5 elasticsearch_and_cassandra_25 / elasticsearch_and_cassandra_mnesia / 95cfce5 internal_mnesia_25 / internal_mnesia / 95cfce5 dynamic_domains_mssql_mnesia_25 / odbc_mssql_mnesia / 95cfce5 riak_mnesia_24 / riak_mnesia / 95cfce5 graphql_server_SUITE:admin_http:clustering_http_tests:remove_node_test{error,{{badmatch,{error,econnrefused}},
[{rest_helper,fusco_request,7,
[{file,"/home/circleci/project/big_tests/tests/rest_helper.erl"},
{line,185}]},
{rest_helper,make_request,1,
[{file,"/home/circleci/project/big_tests/tests/rest_helper.erl"},
{line,114}]},
{rest_helper,make_request,1,
[{file,"/home/circleci/project/big_tests/tests/rest_helper.erl"},
{line,121}]},
{graphql_server_SUITE,remove_node_test,1,
[{file,"/home/circleci/project/big_tests/tests/graphql_server_SUITE.erl"},
{line,210}]},
{test_server,ts_tc,3,[{file,"test_server.erl"},{line,1783}]},
{test_server,run_test_case_eval1,6,
[{file,"test_server.erl"},{line,1292}]},
{test_server,run_test_case_eval,9,
[{file,"test_server.erl"},{line,1224}]}]}} graphql_server_SUITE:admin_http:clustering_http_tests:stop_node_test{error,{{badmatch,{error,econnrefused}},
[{rest_helper,fusco_request,7,
[{file,"/home/circleci/project/big_tests/tests/rest_helper.erl"},
{line,185}]},
{rest_helper,make_request,1,
[{file,"/home/circleci/project/big_tests/tests/rest_helper.erl"},
{line,114}]},
{rest_helper,make_request,1,
[{file,"/home/circleci/project/big_tests/tests/rest_helper.erl"},
{line,121}]},
{graphql_server_SUITE,stop_node_test,1,
[{file,"/home/circleci/project/big_tests/tests/graphql_server_SUITE.erl"},
{line,215}]},
{test_server,ts_tc,3,[{file,"test_server.erl"},{line,1783}]},
{test_server,run_test_case_eval1,6,
[{file,"test_server.erl"},{line,1292}]},
{test_server,run_test_case_eval,9,
[{file,"test_server.erl"},{line,1224}]}]}} pgsql_mnesia_25 / pgsql_mnesia / 95cfce5 pep_SUITE:pep_tests:unsubscribe_after_presence_unsubscription{error,
{{badmatch,
[{xmlel,<<"message">>,
[{<<"from">>,
<<"alice_unsubscribe_after_presence_unsubscription_2594@localhost">>},
{<<"to">>,
<<"bob_unsubscribe_after_presence_unsubscription_2594@localhost/res1">>},
{<<"type">>,<<"headline">>}],
[{xmlel,<<"event">>,
[{<<"xmlns">>,
<<"http://jabber.org/protocol/pubsub#event">>}],
[{xmlel,<<"items">>,
[{<<"node">>,<<"ezNPIrAnnss+oZPPqlnSLg==">>}],
[{xmlel,<<"item">>,
[{<<"id">>,<<"salmon">>}],
[{xmlel,<<"entry">>,
[{<<"xmlns">>,
<<"http://www.w3.org/2005/Atom">>}],
[]}]}]}]},
{xmlel,<<"headers">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/shim">>}],
[]}]}]},
[{pep_SUITE,'-unsubscribe_after_presence_unsubscription/1-fun-0-',2,
[{file,"/home/circleci/project/big_tests/tests/pep_SUITE.erl"},
{line,384}]},
{escalus_story,story,4,
[{file,
"/home/circleci/project/big_tests/_build/default/lib/escalus/src/escalus_story.erl"},
{line,72}]},
{test_server,ts_tc,3,[{file,"test_server.erl"},{line,1782}]},
{test_server,run_test_case_eval1,6,
[{file,"test_server.erl"},{line,1291}]},
{test_server,run_test_case_eval,9,
[{file,"test_server.erl"},{line,1223}]}]}} mysql_redis_25 / mysql_redis / 95cfce5 mssql_mnesia_25 / odbc_mssql_mnesia / 95cfce5 smart_markers_SUITE:regular:one2one:marker_for_thread_can_be_fetched{error,
{{fetch_marker,ok,
[{times,50,
{error,
{badmatch,[]},
[{smart_markers_SUITE,'-verify_marker_fetch/4-fun-6-',3,
[{file,
"/home/circleci/project/big_tests/tests/smart_markers_SUITE.erl"},
{line,405}]},
{mongoose_helper,do_wait_until,2,
[{file,
"/home/circleci/project/big_tests/tests/mongoose_helper.erl"},
{line,374}]},
{escalus_story,story,4,
[{file,
"/home/circleci/project/big_tests/_build/default/lib/escalus/src/escalus_story.erl"},
{line,72}]},
{test_server,ts_tc,3,
[{file,"test_server.erl"},{line,1782}]},
{test_server,run_test_case_eval1,6,
[{file,"test_server.erl"},{line,1291}]},
{test_server,run_test_case_eval,9,
[{file,"test_server.erl"},{line,1223}]}]}}]},
[{mongoose_helper,do_wait_until,2,
[{file,"/home/circleci/project/big_tests/tests/mongoose_helper.erl"},
{line,371}]},
{escalus_story,story,4,
[{file,
"/home/circleci/project/big_tests/_build/default/lib/escalus/src/escalus_story.erl"},
{line,72}]},
{test_server,ts_tc,3,[{file,"test_server.erl"},{line,1782}]},
{test_server,run_test_case_eval1,6,
[{file,"test_server.erl"},{line,1291}]},
{test_server,run_test_case_eval,9,
[{file,"test_server.erl"},{line,1223}]}]}} riak_mnesia_24 / riak_mnesia / 95cfce5 mssql_mnesia_25 / odbc_mssql_mnesia / 95cfce5 |
The goal of this PR is to deliver incoming messages with the use of GraphQL subscriptions.
Such functionality existed for REST API, and it used SSE (Server-Sent Events) with Lasse.
This GraphQL solution is using SSE as well.
Subscription execution
According to GraphQL specification, executing a subscription should return a Response Stream, that will deliver the events to the subscriber. As the
graphql
library executes subscriptions the same way as queries, the subscription needs to be executed several times:null
indata
, and a new Stream inaux
, which corresponds to the Source Stream from the GraphQL docs.null
or the processed Event to send to the client. This step is roughly equivalent to MapSourceToResponseEvent - to implement it fully according to the specs, one would need to reimplement query execution in thegraphql
library, which seems too complicated for now.terminate
event. This is an opportunity to clean up all stream resources. It implements unsubscribe from the specs.SSE Handler
The new
mongoose_graphql_sse_handler
module handles requests to the/sse
sub-path. It prepares and executes the requested subscription, and then listens for incoming messages. Each received message triggers delivery of the event. Only GET requests are accepted, which follows the specs, and is enforced bylasse_handler
.subscribeForMessages
This subscription is added to both Client and Admin API. It returns messages in the same format as
getLastMessages
. It skips stanzas other than messages, just like the REST API. We could extend it when needed.Data structures:
{route, From, To, Acc}
, just like in the REST API. We could amend it later.Other changes
GET and POST requests are now accepted for queries and mutations, and they accept the parameters in a query string and request body, respectively. This follows the GraphQL recommendation.