-
-
Notifications
You must be signed in to change notification settings - Fork 36
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 configurable number of connection attempts #46
Conversation
* default value=2 (->1 retry) * add variable conn_error * implement each conn.make_request in a try-except structure and set conn_error true if an exception occurs
try: | ||
self._conn.make_request(PROP_WRITE_HANDLE, value) | ||
except Exception as ex: |
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 don't currently have a test device at hand to check this, but wouldn't it make more sense to perform the error&retry checking inside make_request
or leave the whole re-try machinery for upstreams to handle?
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.
Inside the make_request function (connection.py) possible errors are fetched. But the calling instance (eg. update function) must recognize and handle the error. That's the reason for the stacktrace.
You don't need a real test device, try it with a random mac like 11:22:33:44:55:66.
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.
Okay, I found a test device and did some quick testing.
Now, I think it's better to let the exceptions bubble up instead of having a device global error flag (e.g., if you query multiple different things, some of them may succeed and you can still display that information to the user), and handle the exception at user's end.
In the cli, instead of checking for the the error flag, it would be better to do something like this for the @cli.group
to capture all exceptions: https://stackoverflow.com/questions/44344940/python-click-subcommand-unified-error-handling/44347763#44347763
* add cli option --connectionattempts
After the last commits eq3cli.py also works perfect!
Finally README.md has to be updated. |
try: | ||
self._conn.make_request(PROP_WRITE_HANDLE, value) | ||
except Exception as ex: |
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.
Okay, I found a test device and did some quick testing.
Now, I think it's better to let the exceptions bubble up instead of having a device global error flag (e.g., if you query multiple different things, some of them may succeed and you can still display that information to the user), and handle the exception at user's end.
In the cli, instead of checking for the the error flag, it would be better to do something like this for the @cli.group
to capture all exceptions: https://stackoverflow.com/questions/44344940/python-click-subcommand-unified-error-handling/44347763#44347763
if not dev.connection_error: | ||
click.echo("Current target temp: %s" % dev.target_temperature) | ||
if target: | ||
click.echo("Setting target temp: %s" % target) | ||
dev.target_temperature = target | ||
else: | ||
click.echo("Connection error") |
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.
if not dev.connection_error: | |
click.echo("Current target temp: %s" % dev.target_temperature) | |
if target: | |
click.echo("Setting target temp: %s" % target) | |
dev.target_temperature = target | |
else: | |
click.echo("Connection error") | |
if dev.connection_error: | |
click.echo("Connection error") | |
return | |
click.echo("Current target temp: %s" % dev.target_temperature) | |
if target: | |
click.echo("Setting target temp: %s" % target) | |
dev.target_temperature = target |
It is better to return early for error cases, but see my commentary above regarding to how to handle errors in a nicer way with no need for adjusting each and every command separately.
eq3bt/eq3cli.py
Outdated
@@ -22,16 +22,17 @@ def validate_mac(ctx, param, mac): | |||
@click.group(invoke_without_command=True) | |||
@click.option('--mac', envvar="EQ3_MAC", required=True, callback=validate_mac) | |||
@click.option('--interface', default=None) | |||
@click.option('--connectionattempts', default=2) |
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.
@click.option('--connectionattempts', default=2) | |
@click.option('--retry', default=2) |
Or --retries
would be shorter and still understandable name 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's okay for me. But 'connectionattempts' is not the same as 'retries'. The change must also be reflected in eq3btsmart.py and connection.py. See commit 603b391
I realized one more thing, maybe it would make sense to lower the timeout for the tries in this same PR. At the moment it takes very long to retry, and most of the times if the device has not responded in a couple of seconds it likely makes more sense to retry instead of waiting long for an answer. |
Then we should make 'timeout' configurable. OK? |
The last few commits should address your previous comments as far as they pertain the issue this PR is supposed to solve. Hence, from my side, I believe it should be ready to be merged. As for your other suggestions, such as the error handling overall or the question about time delay in case when a connection could not be established, I think these are certainly worth investigating. However, at the same time, they do not directly pertain the issue of this PR, which is why they should rather be the subject of a separate PR. For instance, in order to properly solve the issue with the time delay, one has to ultimately extend the bluepy interface, since this is precisely where I believe the delay is coming from. |
I agree that the timeout handling should not be a part of this PR and is something to be considered later on, but the error handling should definitely be cleaned to keep the code base clean and maintainable. The retry logic should only involve changes inside of So, after a brief investigation, I think the best option would be using a retry library like tenacity and simply decorate all I/O doing calls inside |
Fixes #34