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

integrated client side keep alive timeout #129

Closed
wants to merge 2 commits into from

Conversation

konradmichael
Copy link
Contributor

This is my implementation for fixing the Issue #123. This time it also includes Unit-Tests

There are three main changes:

  1. Introduction of parameter 'keepAliveTimeout' (default:10) - Code comes from 'vietj's branch
  2. Added IdleStateHandler for closing the connection, if no input is coming within timeout
  3. keepAliveHandler will react on READER_IDLE

to Point3:
If you only send messages with QoS-0 you wont get anything from the broker. This way you cannot identify the state of the server connection. If you need to know if the server is responding you have to include the READER_IDLE.
Consequence of this is, that you usually send two PINGREQ, one for WRITER_IDLE and one for READER_IDLE.

I appreciate any help on this topic

@vietj
Copy link
Contributor

vietj commented Mar 28, 2019

keepAliveTimeout is for the server not the client, also all tests have not been ported

@vietj
Copy link
Contributor

vietj commented Mar 28, 2019

sorry you just renamed on the server the 1.5 factor variable to keepAliveTimeout which was not clear initially

@vietj
Copy link
Contributor

vietj commented Mar 28, 2019

I also did a modification of the MqttServerImpl to support disabling of responses to test the case where the server will not send a ping response in time, can you port this + the test as well to have this case covered ?

@konradmichael
Copy link
Contributor Author

konradmichael commented Mar 29, 2019

keepAliveTimeout is for the server not the client, also all tests have not been ported

I have no Idea what that means? Can you please be more clear? What tests have to be ported?

sorry you just renamed on the server the 1.5 factor variable to keepAliveTimeout which was not clear initially

Sometimes it is more helpful to use a meaningful variable name, timeout is very general. But if you want it to be reverted, just say so
It is a leftover of some test implementation.

I also did a modification of the MqttServerImpl to support disabling of responses to test the case where the server will not send a ping response in time, can you port this + the test as well to have this case covered ?

Yes you made a modification. But after reviewing it, I have not found the use of it, that's why I did not integrate it. All the option did, was to stop the server-side timeout. It did not disable all keepAlive handling (PINGREQ / PINGRESP). So the option name was also misleading.
Also you see, that the test still worked without that option, so again why would you need that option.

I also tried to make some more tests, but they were full of magic numbers and the outcome would not have been meaningful. E.g. How do you test that your connection does NOT timeout ? :)
Testing is an art ...

@konradmichael
Copy link
Contributor Author

The travis checks are failing because of a blocked port :)
Problem here seems to be the parallel run of multiple builds / tests. It might be a good idea to revert the tests to use dynamic free ports.

    try (ServerSocket socket = new ServerSocket(0)) {
        socket.setReuseAddress(true);
        return socket.getLocalPort();
    }

@vietj
Copy link
Contributor

vietj commented Mar 29, 2019

I see what you mean now, indeed it is not necessary, in my test I made the mistake to use a setKeepAliveTimeout larger than setKeepAliveTimeSeconds on the client which required this change.

I'll make a few comments in the PR.

You want to test that the client does not timeout because it receives ping in time from the server ?

async.complete();
});
}));
async.await(4000);
Copy link
Contributor

Choose a reason for hiding this comment

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

this is not needed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok :) But I would like to keep the timeout.
The last time i was running this test and it failed, it did not stop. I havent tried to find the default timeout.
If you know a better way, feel free to change

Copy link
Contributor

Choose a reason for hiding this comment

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

it's really not useful here, Vert.x Unit will anyway consider the test is not finished until async.complete() is called even though the test method returns

async.complete();
});
}));
async.await(4000);
Copy link
Contributor

Choose a reason for hiding this comment

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

this is not needed

startServer(ctx);
Async async = ctx.async();
MqttClientOptions options = new MqttClientOptions();
options.setKeepAliveTimeSeconds(1);
Copy link
Contributor

@vietj vietj Mar 29, 2019

Choose a reason for hiding this comment

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

use a larger value than 1

Currently this will tell the server to disconnect after 1 seconds it receives a ping, as the client sends a ping after 1 second, so the server might try to disconnect after 2 seconds, this can race with the fact that we test the client will close the connection and not the server, which can happen in CI and report false negatives.

I think the value 6 is a good trade off: the client will disconnect after 7 seconds (6 + 1) and the server would disconnect after 9 seconds which gives a 2 seconds delta.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right. I usually try to keep these values as tiny as possible to reduce test runtime.

@konradmichael
Copy link
Contributor Author

You want to test that the client does not timeout because it receives ping in time from the server ?

That is a complex test with many magic numbers. From my point of view it is very hard to make such a test that looks reasonable. What interval is long enough to wait, so that this is a real test ...

It is always pretty tough, to test that nothing happens :)

I will update the PR on monday, waiting for some more responses and reviews.

@vietj
Copy link
Contributor

vietj commented Jun 11, 2019

@ppatierno can you finish the review and merge for 3.8 / master ?

@vietj vietj added this to the 3.8.0 milestone Jun 11, 2019
case WRITER_IDLE:
// send ping or broker will close connection
ping();
break;
Copy link
Member

Choose a reason for hiding this comment

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

Can we do "fall through" here? Both cases have the same ping() instruction

}
}
}
});

if(this.options.getKeepAliveTimeout() > 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Space after if

@@ -243,11 +243,10 @@ private void handleConnect(MqttConnectMessage msg) {
if (msg.variableHeader().keepAliveTimeSeconds() != 0) {

// the server waits for one and a half times the keep alive time period (MQTT spec)
int timeout = msg.variableHeader().keepAliveTimeSeconds() +
msg.variableHeader().keepAliveTimeSeconds() / 2;
int keepAliveTimeout =(int) (msg.variableHeader().keepAliveTimeSeconds() * 1.5);
Copy link
Member

Choose a reason for hiding this comment

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

space after =

import static org.junit.Assert.assertEquals;

/**
* MQTT client keep alive tests using a Vert.x MQTT server to accomodate testing.
Copy link
Member

Choose a reason for hiding this comment

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

I guess this comment is wrong, the test is about MQTT server not client.

@ppatierno
Copy link
Member

@vietj @konradmichael I have left a few comments but after them I think we are good to go.

@vietj
Copy link
Contributor

vietj commented Jul 14, 2019

it seems the test did fail in CI

@vietj vietj modified the milestones: 3.8.0, 3.8.1 Jul 19, 2019
@vietj
Copy link
Contributor

vietj commented Aug 20, 2019

tests still don't pass, we should have a CI passing to accept this PR - anybody wanting to contribute please step up and help

@vietj vietj modified the milestones: 3.8.1, 3.8.2 Aug 23, 2019
@vietj vietj modified the milestones: 3.8.2, 3.8.3 Oct 4, 2019
@vietj vietj modified the milestones: 3.8.3, 3.8.4 Oct 22, 2019
@vietj vietj modified the milestones: 3.9.3, 3.9.4 Sep 17, 2020
@vietj
Copy link
Contributor

vietj commented Oct 7, 2020

I'm looking at finishing this PR and it seems that the client (which is visible in MqttClientKeepAliveTest) will send 2 pings simultaneously after 2 seconds because the IdleStateHandler will trigger for read and write. That seems incorrect to me.

@vietj
Copy link
Contributor

vietj commented Oct 7, 2020

See #173

@vietj vietj closed this Oct 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

4 participants