-
-
Notifications
You must be signed in to change notification settings - Fork 75
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
[feature] Added optional clean insights measurement collection #360 #365
Conversation
5724918
to
4d7d04a
Compare
4d7d04a
to
d564b07
Compare
openwisp_utils/measurements/tasks.py
Outdated
time.sleep(5) | ||
logger.error( | ||
f'Maximum tries reach to upload Clean Insights measurements. Error: {message}' | ||
) |
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.
Let's use the retry mechanism offered by the requests library that you know of ;)
f4c7288
to
a6dbf26
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.
Let's not mention clean insights in the code and comments except in the README.
Let's not assume people reading the code know what clean insights is, let's use a generic term "Usage Metric Collection".
See my comments below.
|
||
We collect data on OpenWISP usage to gauge user engagement, satisfaction, | ||
and upgrade patterns. This informs our development decisions, ensuring | ||
continuous improvement aligned with user needs. |
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.
Let's add a paragraph introducing and linking to cleaninsights.
}, | ||
) | ||
assert response.status_code == 204 | ||
except Exception as 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.
are you absolutely sure this code works also when the server does not reply 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.
I have tested the following scenarios:
- Trying to establish connection to the port where no application is listening - Check the command output on Hastebin
- When the server time outs (hangs) after establishing the connection - Check the command output on Hastebin
I have added a test case for this https://github.com/openwisp/openwisp-utils/pull/365/files#diff-118b67d11be9c05a77bccfedd814f41974ca3fb2bfd21eb010350faf22d59d3bR180-R196
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 used this code for the mock server
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
class MyHandler(SimpleHTTPRequestHandler):
def do_GET(self):
import time
time.sleep(40000000)
def run_server():
server_address = ('', 8000)
httpd = TCPServer(server_address, MyHandler)
print(f"Server running on http://localhost:{server_address[1]}")
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
finally:
httpd.server_close()
if __name__ == "__main__":
run_server()
""" | ||
This function takes a category and data representing usage metrics, | ||
and returns a list of events in a format accepted by the | ||
Clean Insights Matomo Proxy (CIMP) API. | ||
|
||
Read the "Event Measurement Schema" in the CIMP documentation: | ||
https://cutt.ly/SwBkC40A | ||
""" |
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 intentionally left this reference to Clean Insights here to remind us in the future why we are using this specific structure.
7e1564e
to
59f9490
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.
Can you look into why the code coverage is decreasing?
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 think the metric collection logic is good to merge, but I think the retryable_request
needs a bit more love so we can reuse it in other OpenWISP python modules too.
openwisp_utils/utils.py
Outdated
def retryable_request(method, timeout=(4, 8), max_retries=3, **kwargs): | ||
request_session = requests.Session() | ||
retries = Retry( | ||
total=max_retries, | ||
backoff_factor=1, | ||
status_forcelist=[429, 500, 502, 503, 504], |
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 new utility function will be useful, please allow to custoimize the arguments passed to Retry()
, eg:
- backoff_factor
- backoff_jitter
- status_forcelist
- allowed_methods
- add another argument called retry_kwargs=None
Then I recommend doing something like:
if retry_kwargs is None:
retry_kwargs = {}
retry_kwargs.update(dict(
total=max_retries,
backoff_factor=backoff_factor,
backoff_jitter=backoff_jitter,
status_forcelist=status_forcelist,
allowed_methods=allowed_methods
))
retries = Retry(**retry_kwargs)
This will allow us to reuse this function in other modules because as you know it's a common need.
Please add this function to the README and make sure there's at least one unit test dedicated to this function only.
Save each upgrade in a differet OpenwispVersion object
- Changed leftover references to CleanInsights Events in tests
31db451
to
35d0cda
Compare
backoff_factor=1, | ||
backoff_jitter=0.0, | ||
status_forcelist=(429, 500, 502, 503, 504), | ||
allowed_methods=('HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE', 'POST'), |
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.
one more time, let's not use mutable default arguments for the reasons described here:
https://dev.to/sharmapacific/mutable-default-arguments-in-python-22ce
We have already been hit a few times by obscure bugs which originated from using mutable default arguments, let's not repeat the same mistakes.
This applies to timeout, status_forcelist, allowed_methods.
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.
After giving a second look to the mutable argument subject, I think it's ok since we don't return the mutable objects nor manipulate these inside the function, so we are not risking to be hit by weird bugs and this usage is fine.
@nemesifier Tuples in Python are immutable. That's why I used tuples and not lists. 😄 |
Closes #360
Changes
Screenshots
Checklist