-
Notifications
You must be signed in to change notification settings - Fork 125
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
fix(graphql-transport-ws): ensure result message is processed before … #466
Conversation
Hi! Could you explain (on a higher level) what exactly this does, why it's needed/an improvement and document the change in behaviour with a test? I don't fully understand it yet. |
while (message is CompleteMessage && | ||
nextOrErrorMsgWaitMap.containsKey(message.id)) { | ||
await Future.delayed(const Duration(milliseconds: 100)); | ||
} |
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.
could this potential endless loop be replaces using a completed? should there be a timeout to avoid hanging forever?
I'm using websocket connection not only for subscriptions, but also for single result operations. This pr is to fix 2 bugs that occur for single-result operations. this part of code in graph-transport-ws.dart causes race condition, if "complete" message is received shortly after "next" message, it's possible that "complete" message is processed before "next" message (because of this step try {
final messageMap = await options.graphQLSocketMessageDecoder(msg);
message = parseMessage(messageMap!, options.parser);
} catch (e, s) {
throw WebSocketLinkParserException(
// TODO: should not be ConnectionAck
message: ConnectionAck(),
originalException: e,
originalStackTrace: s,
);
} this part of code closes connection whenever there are no more operations in process, which is not desired, because I want to do a bunch of single-result operations before I do subscription released.then((_) {
if (locks == 0) {
// and if no more locks are present, complete the connection
...
}
}
) |
Thanks! I can see how awaiting the decoded message is problematic. try {
final messageMap = await options.graphQLSocketMessageDecoder(msg);
message = parseMessage(messageMap!, options.parser);
} catch (e, s) {
throw WebSocketLinkParserException(
// TODO: should not be ConnectionAck
message: ConnectionAck(),
originalException: e,
originalStackTrace: s,
);
} I observe the following:
So, the final messageMapFutureOr =
options.graphQLSocketMessageDecoder(msg);
final Map<String, dynamic>? messageMap;
if (messageMapFutureOr is Future) {
messageMap = await messageMapFutureOr;
} else {
messageMap = messageMapFutureOr;
} This would avoid this problem by processing the message synchronously, if possible. But it would be a breaking change, so let's investigate on how to handle the path with a future: int waitTimeOut = 0;
while (message is CompleteMessage &&
nextOrErrorMsgWaitMap.containsKey(message.id)) {
await Future.delayed(const Duration(milliseconds: 100));
waitTimeOut++;
// if next or error message is not arrived or processed in 60 seconds, break the loop
if (waitTimeOut >= 600) {
break;
}
} This avoid the endless loop, but I would prefer a solution without polling. How about making the
And before removing the |
Sounds reasonable. There are already similar tests in |
I'll add tests in next couple of weeks, kinda tied up at the moment. I can't make another pr for |
the new commit fix(graphql_transport_ws): completer error Future already completed fixes error
For single-result operations, error message can complete future, but |
We are needing similar things. I'm wondering how this PR is coming? Thanks for all your work on it! |
very busy at the moment, I need at least 1 day to do tests, my estimation is November, you can point to my repo in the mean time
If you have time to do tests, feel free to make a PR to my repo |
…complete message; do not close connection if keepalive is on
…d complete message wait loop
…ync tasks management
tests are done |
Thanks! LGTM |
fix(graphql-transport-ws): ensure result message (next or error) is processed before complete message; do not close connection if keepalive is on