-
Notifications
You must be signed in to change notification settings - Fork 0
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
Refactor the JSON-RPC connection #52
base: main
Are you sure you want to change the base?
Conversation
6855b25
to
755c7f5
Compare
Can you explain to me the different purposes of the modules |
@maehjam It is less mixed up than it was, but I get that it may still be under documented. grisp_connect_jsonrpc is only doing JSON-RPC encoding/decoding, grisp_connect_connection encapsulate a JSON-RPC connection, and grisp_connect_client encapsulate the girps_connect client protocol. |
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.
- The logger changes and architecture changes of the websocket connection shouldn't be in the same PR. Both are changes in parts that are hard to test. They each need very careful testing and probably manual testing in addition to the automatic testing.
- Is this working with the current
grisp_manager
implementation or do we need to adjustgrisp_manager
as well?
reset_log() -> | ||
reset_log(undefined). | ||
|
||
reset_log(LasSeq) -> |
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.
You could have just fixed last_seq/0
to do that. Now we do more or less the same twice.
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.
True, it ended up like this because I tried a lot of different ways to fix the issue, and the last working one could have been done in last_seq/0. I could change that.
@@ -20,7 +20,6 @@ wait_connection() -> | |||
wait_connection(30_000). | |||
|
|||
wait_connection(0) -> | |||
ct:pal("grisp_connect_ws state:~n~p~n", [sys:get_state(grisp_connect_ws)]), |
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.
Why remove the logs?
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.
Because now there is not always a permanent connection process, it may not be there and instead of trying to do some error handling and showing the state only when the connections there, given it is only debug information I just removed the line.
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.
You have connect and disconnect in every test case. I would do that in init_per_testcase
and end_per_testcase
.
src/grisp_connect_connection.erl
Outdated
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.
I feel with the timeouts and the distinction between connected and disconnected in handle_call
this would be much better readable as a gen_statem
. The module name is a bit strange, I liked grisp_connect_ws
better.
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.
It does way more than the old grisp_connect_ws. This remove complexity not related to the API from the client and API and could be reused easily. What would be the states if it was a statem ?
I only change the logging int he new code, I didn't touch the logging in the old code. What do you mean by these change shouldn't go together ? |
- Small changes in tests from review feedback
This PR is stuck for a while now. Adding 1860 Lines and removing 430 is clearly beyond the size of reviewability (max 500 lines). How do we want to proceed with this? @sylane can you split it up in several PRs? Also from what I can see so far: it looks in parts more like a rewrite than a refactoring. I'm not sure if that is due to too many refactoring steps stacked on top of each other so it only looks like a rewrite? Rewriting or large refactors have a tendency to sneak in new bugs, so therefore require substantial improvement of testing at the same time: is that the case here? How is the relationship between this code and DAB? Will this eventually end up in DAB? Parts of it? I don't want to have to maintain two forks of the same thing if that is the actual case. |
@peerst This is already only some part of a bigger changeset that I split so it was simpler to review... Some changes already got merged in, but there is still more changes pending. The changes here are to go toward having a self-contained independent json-rpc client instead of having json-rpc logic spread everywhere in grisp-connect. So the connection is indeed a rewrite, but all the rest are changes to mostly remove things that are now abstracted by the new connection. I don't think I could easily split the changes further. For the testing, I wrote more tests, and I made the code more test-friendly, as the json-rpc connection can be tested completely independently. If we want more tests for it, I could write more, this shouldn't be complicated. |
#{formatter => {grisp_connect_logger_bin, #{}}, | ||
filter_default => log, | ||
filters => [ | ||
{disable_progress, {fun logger_filters:progress/2, stop}} |
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.
Note that If this should ship in the default dettings for a grisp_connect based project we need to open a PR for rebar3_grisp/ grisp_tools to update the configuration for new generated user projects;
(rebar3 grisp configure)
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.
I am not 100% sure that it make things better. It looked better for me, and this is the common solution I found about our problem with logging certificate, but others should test it too.
src/grisp_connect_client.erl
Outdated
when Conn =/= undefined -> | ||
ReqCtx = #{on_result => OnResult, on_error => OnError}, | ||
Params2 = maps:put(type, Type, Params), | ||
case jarl:post(Conn, Method, Params2, ReqCtx) of |
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.
Why do you have jarl:request
and jarl:post
and you only use jarl:post
? Json RPC does not have the concept of a post
but only request/notify
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.
Also, in the jarl application you have this 700+ lines gen_statem
that implements JsonRPC message handling and GUN logic together.
Could these 2 concepts be split in 2 modules in Jarl,as it was in grisp_connect
before this PR?
The jarl_connection module looks already too big
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.
As the idea was first to consolidate the JSON-RPC in a single place in grisp_connect first, this is what I did with jarl_connection, but then I moved it out of grisp_connect to make the PR more compact. Maybe this could be refactored again to split again, not sure if it is needed now though, I am open to it. The main reason I think it was more important before is because the guns management and the json-rpc was done in different processes before, now it is done in the same process.
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.
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.
@sylane still... why post
instead of request
?
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.
I'm also confused what post
is. There is no documentation in jarl
about it.
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.
post it to asynchronously post a request, request is doing a post and wait for the response so it is synchronous
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.
When using post, you need to handle the asynchronous messages with either a response or an error.
Sorry, I still don't think I'm able to review this. It is too much changes at once. Now, we have changes here and a new app I feel before we can review the changes here, we need to review Furthermore, I have to note: Even when we move a big chunk of this rewrite in a separate library that is still a big rewrite. We already have two JSON-RPC client implementations here in If we want this big rewrite. I would prefer that we first develop We should make sure a library like |
This PR is only around 330+330- lines if you don't count tests, docs and config, it is big but I don't think it is unrasonable. I understand that moves some review work to jarl, but it is now a self-contains library with limited scope and API. They weren't any documentation with the old jrpc-code, at least now theres is well defined type specifications. I could add more documentation, this is not a problem, but would that change your mind ? |
@sylane I think we should discuss jarl usage, architecture and API. This PR would be ok but it relies on us accepting jarl as is.
|
Just to clear it up: The examples I mentioned about the function naming Thanks @ziopio for the proposal on how we can continue here. That is for sure one way. I would like a decision from @peerst and the rest of the team on how we proceed, before we put too much time into it. That can be discussed after the first point of presenting |
6d741a5
to
c8495b4
Compare
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.
I reviewed the first 8 files and found that the JSON-RPC API must be broken, since errors are not handled. I was wondering whether the tests wouldn't catch that. Please extend grisp_connect_api_SUITE
to better cover the API. It only tests two methods.
I stop my review here till the tests pass.
There are already some change requests in the inline comments.
One other thing I noticed is that rebar.lock
is missing. With the new jarl
library as a dependency it should be updated.
CHANGELOG.md
Outdated
- The name of the grisp_connect configuration key to control the timeout of | ||
individual JSON-RPC requests changed from ws_requests_timeout to | ||
ws_request_timeout. | ||
- Le default log filter changed to trying to filter out only some messages to |
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.
"Le" -> "The".
Maybe mention that this is only done for testing and development. (I see log level in prod is notice
so we don't need it there.)
config/dev.config
Outdated
] | ||
}} | ||
]} | ||
]} | ||
|
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.
Unnecessary newline.
## Fixed | ||
|
||
- The client is now waiting 1 second before trying to reconnect when it gets | ||
disconnected from the server. |
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.
I'm trying to find this. Is this done here or in jarl
?
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.
It is done in in grisp_connect_client, in the connecting function.
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.
I did look again and found it in waiting_ip
. So that is a counter intuitive place to do it. I was expecting it in connecting
somewhere, for example in enter
there. Is there some deeper reason to put it in waiting_ip
that I don't see?
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.
It doesn't make much sense to not check again if the IP is available after a connection error, so going back to waiting_ip seems better, and as we want to wait between each ip checks, better leveraging this than behaving differently if we were connected or not before then.
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.
But it's not leveraged. The waiting between waiting_ip
is implemented in line 156 and the waiting between connects in line 144. They are not related at all.
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.
It is, because by switching to state waiting_ip
from either the connecting
or connected
state you will have the correct delay. Maybe using repeat_state
instead of next_state
at line 156 and not registering a new state_timeout
would make it clearer for you ? This way the timeout would only be setup in waiting_ip
enter function.
docs/grisp_connect_architecture.md
Outdated
- Perform synchronous requests | ||
- Start asynchronous requests | ||
- Reply to a request | ||
- Send and error result for a request |
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.
"and" -> "an"
docs/grisp_connect_architecture.md
Outdated
- Reply to a request | ||
- Send and error result for a request | ||
- Send asynchronous notifications | ||
- Send generic errors |
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.
That formulation is a bit unclear. Do you mean the automatic sending for predefined JSON-RPC errors from the JSON-RPC specifications? Then instead of "generic errors" rephrase it to "predefined JSON-PRC errors".
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.
This is something we figured out wasn't even in the JSON-RPC spec, and I removed it. O I will remove the generic error line.
docs/grisp_connect_architecture.md
Outdated
- Send generic errors | ||
|
||
When performing an asynchronous request, the caller can give an opaque context | ||
term, that will given back when receiving a response or an error for this |
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.
"that will be given back"
{filter_out_progress, { | ||
fun grisp_connect_logger_bin:filter_out/2, | ||
{supervisor, report_progress}}} | ||
{disable_progress, {fun logger_filters:progress/2, stop}} |
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.
It would be good to keep the comment why we do that here and also add it to local.config
, test.config
.
notify(Method, Type, Params) -> | ||
Rpc = {notification, Method, maps:put(type, Type, Params)}, | ||
grisp_connect_jsonrpc:encode(Rpc). | ||
% @doc Handles requests, notifications and errors from grisp.io. |
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.
I see it only handling notifications and requests, not errors.
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.
It wasn't before the refactor IIRC, so I didn't add it.
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.
In fact, the request errors are handled in grisp_cllient: https://github.com/grisp/grisp_connect/blob/sylane/cleanup-connection/src/grisp_connect_client.erl#L260
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.
It was done before the refactoring (you can clearly see it in the diff) and it had a totally different documentation.
So that documentation is about your change and it doesn't fit. Fix it.
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.
You are right, and I remembered that and posted the second comment about where the error is handled. Now the error are handled in a generic way in grisp_connect_client, line 260
{error, already_updating} -> | ||
{error, -11, already_updating, undefined, ID}; | ||
{error, already_updating, undefined, undefined, ID}; |
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.
This error is not defined in grisp_connect_client
.
{error, grisp_updater_unavailable} -> | ||
{error, -10, grisp_updater_unavailable, undefined, ID}; | ||
{error, grisp_updater_unavailable, undefined, undefined, ID}; |
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.
All the error tuples are not handled as return values is grisp_connect_client:handle_connection_message/2
.
Changed
individual JSON-RPC requests changed from ws_requests_timeout ot
ws_request_timeout.
filtering out all progress messages, as it wasn't working reliably.
process handling a connection and dying when the connection is closed.
road for namespaces. foo.bar.Buz is parsed into [foo, bar, <<"Buz">>] (if foo
and bar are already existing atoms, but 'Buz' is not).
Fixed
disconnected fomr the server.