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

Implement RetryingClient #324

Merged
merged 1 commit into from
Jul 13, 2021
Merged

Conversation

martinnj
Copy link
Contributor

@martinnj martinnj commented Jun 17, 2021

Goal here is basically to help with #307.
And takes inspiration from this comment

The idea is a thin "wrapper client" that does nothing but forward calls and retry as appropriate.
The features are as follows:

  • Takes any Client or Client-like class.
  • Configurable number of retries.
  • Configurable sleep between retries. (Don't think it's really a good idea in a cache, but it was easy, so here we are.)
  • Allows retrying only for specific Exception types.
  • Allows skipping retries for specific Exception types.

I haven't written tests yet since I wanted some opinions on the interface/constructor first.

Currently the class uses __getattr__ to pass through any attributes/methods that isn't present on itself to the inner client.
It also passes through dir() calls to the inner client to allow for checking available methods, attributes, etc.
Is this an acceptable implementation or is it too opaque?

I also did a more naive implementation, it is commented out in the code.

Feedback and suggestions are welcome.
I'll write the unit-tests ones the feel of the client is more solid.

@cgordon are you the person to go to for this? 😄

Copy link
Collaborator

@cgordon cgordon left a comment

Choose a reason for hiding this comment

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

There are a couple existing "retry" libraries on PyPI, and it is probably worth either implementing their full set of functionality, or just using them directly. Here are the two I found:

https://pypi.org/project/retry/
https://pypi.org/project/retrying/

pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
@martinnj
Copy link
Contributor Author

There are a couple existing "retry" libraries on PyPI, and it is probably worth either implementing their full set of functionality, or just using them directly. Here are the two I found:

https://pypi.org/project/retry/
https://pypi.org/project/retrying/

Was there any specific features from those libraries you where wanting?
Currently the timeout, retry count and exception based actions is implemented.

I didn't look for existing libraries because adding dependencies for something like this would be a shame in my eyes.

@4383
Copy link
Contributor

4383 commented Jun 18, 2021

There are a couple existing "retry" libraries on PyPI, and it is probably worth either implementing their full set of functionality, or just using them directly. Here are the two I found:

https://pypi.org/project/retry/
https://pypi.org/project/retrying/

Tenacity is an interesting implementation and already well used on openstack.

However, I agree with @martinnj , if possible, it would be more interesting to keep pymemcache as a pure python library (I voluntarly ignore six). Maybe by only providing specific retry strategies without tons of configurations. Less is more.

@4383
Copy link
Contributor

4383 commented Jun 18, 2021

Also notice that Wednesday I also started to implement similar features, however, I didn't yet proposed them before today through a pull request. #326

By introspection the passed clients, I dynamically decorate their methods to make them "retryable".

It's not a problem for me if you decide to continue with this version (that of @martinnj). Maybe we could converge our implementations to design and co-author something, it's up to you to decide. I propose you dispose.

@martinnj
Copy link
Contributor Author

It's not a problem for me if you decide to continue with this version (that of @martinnj). Maybe we could converge our implementations to design and co-author something, it's up to you to decide. I propose you dispose.

Wild timing, I'll just wait with spending more time until a collaborator decides either way. :)

@martinnj
Copy link
Contributor Author

martinnj commented Jun 23, 2021

I had some time so I thought I'd give it a shot anyway.

Changes:

  • I had to redo the retry/passthrough logic since I had grossly misunderstood __getattr__.
  • Fixed style issues.
  • Fleshed out docstrings.
  • Added unit tests.

I haven't added a unit-test for the "delay" function. If forced I would time how long the call took and check that it was strictly longer than the delay argument. But I also feel like inserting second long delays in the unit-tests is a bit weird.

Let me know if I should start squashing my commits so there is less bloat in the history.

EDIT: Might've send out an email notification or two too many last night. Sorry about that. Github and me are not always best friends.

@martinnj martinnj requested a review from cgordon June 23, 2021 19:10
@martinnj martinnj marked this pull request as ready for review June 23, 2021 19:19
@martinnj martinnj requested review from jogo and jparise as code owners June 23, 2021 19:19
@cgordon
Copy link
Collaborator

cgordon commented Jun 27, 2021

@martinnj I'm out of town right now and mostly away from my computer. I will have time to look through this next week, apologies for the delay.

@martinnj
Copy link
Contributor Author

@martinnj I'm out of town right now and mostly away from my computer. I will have time to look through this next week, apologies for the delay.

No stress, it's all good.

@4383
Copy link
Contributor

4383 commented Jun 28, 2021

Hello

@martinnj: Please can you also add related doc with some examples of usage?
maybe there https://pymemcache.readthedocs.io/en/latest/getting_started.html

Copy link
Contributor

@4383 4383 left a comment

Choose a reason for hiding this comment

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

Hello see my inline comment about abc

pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/test/test_client_retry.py Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
Copy link
Contributor

@4383 4383 left a comment

Choose a reason for hiding this comment

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

Nice changes, thank you for applying my previous comments.

Here is a couple of new suggestions, they aren't mandatory comments. I think that they can help to improve this feature.

docs/getting_started.rst Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
pymemcache/client/retrying.py Outdated Show resolved Hide resolved
@4383
Copy link
Contributor

4383 commented Jun 29, 2021

Also, I think that it could be worth to reword and to squash your commits into a all in one commit to avoid to spread the history of these changes.

Example:

$ git rebase -i HEAD~12
reword ee1aa4c Add first draft for RetryingClient.
squash 9325a3c Corrections, docstrings and fixes for RetryingClient.
squash 0700983 Stop retring AttributeError and style fixes.
squash eddbe50 Stylefixes for flake8.
squash 6664775 Minor fixes and docstrings for RetryingClient.
squash cf2b44d Add unit-tests for RetryingClient.
squash f08d348 Add RetryingClient example to the getting started docuementation.
squash 71f81bb More robust import of Iterable.
squash b0782c5 0 index retry range.
squash 03d7c48 Reorder imports of tests for pop8ness.
squash eee78cc Sharpen test-case.
squash 5da4090 Simplify argument parsing.

All these changes are related to a single one feature.

4383 added a commit to 4383/pymemcache that referenced this pull request Jun 29, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
4383 added a commit to 4383/pymemcache that referenced this pull request Jun 29, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
4383 added a commit to 4383/pymemcache that referenced this pull request Jun 29, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
4383 added a commit to 4383/pymemcache that referenced this pull request Jun 29, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
4383 added a commit to 4383/pymemcache that referenced this pull request Jun 30, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
4383 added a commit to 4383/pymemcache that referenced this pull request Jun 30, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
4383 added a commit to 4383/pymemcache that referenced this pull request Jul 1, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
4383 added a commit to 4383/pymemcache that referenced this pull request Jul 1, 2021
These changes allow users to activate and configure their socket keepalive.

For now users can configure:
- the enabling of their socket keepalive;
- the time the connection needs to remain idle before TCP starts sending
  keepalive probes;
- the time (in seconds) between individual keepalive probes;
- the maximum number of keepalive probes TCP should send before dropping
  the connection.

This could be used by users who want to handle fine grained failures and
scenarios.

Also this could be another way to handle problems more or less similar
to pinterest#307

This could be in addition of the retry mechanisms
pinterest#324

For now this feature only support Linux platform.
Other systems support could be added through follow up patches.
@martinnj martinnj force-pushed the feature/retrying-client branch from 80f6b3a to d300a2b Compare July 3, 2021 09:06
@martinnj
Copy link
Contributor Author

martinnj commented Jul 3, 2021

Also, I think that it could be worth to reword and to squash your commits into a all in one commit to avoid to spread the history of these changes.

Example:

$ git rebase -i HEAD~12
reword ee1aa4c Add first draft for RetryingClient.
squash 9325a3c Corrections, docstrings and fixes for RetryingClient.
squash 0700983 Stop retring AttributeError and style fixes.
squash eddbe50 Stylefixes for flake8.
squash 6664775 Minor fixes and docstrings for RetryingClient.
squash cf2b44d Add unit-tests for RetryingClient.
squash f08d348 Add RetryingClient example to the getting started docuementation.
squash 71f81bb More robust import of Iterable.
squash b0782c5 0 index retry range.
squash 03d7c48 Reorder imports of tests for pop8ness.
squash eee78cc Sharpen test-case.
squash 5da4090 Simplify argument parsing.

All these changes are related to a single one feature.

Plan was to squash just before merging, since the commits give context to some of the comments in the PR.

Edit:
Thanks for all the feedback btw. :)

@martinnj martinnj force-pushed the feature/retrying-client branch from d300a2b to 52e0238 Compare July 3, 2021 09:08
@4383
Copy link
Contributor

4383 commented Jul 5, 2021

Also, I think that it could be worth to reword and to squash your commits into a all in one commit to avoid to spread the history of these changes.
Example:

$ git rebase -i HEAD~12
reword ee1aa4c Add first draft for RetryingClient.
squash 9325a3c Corrections, docstrings and fixes for RetryingClient.
squash 0700983 Stop retring AttributeError and style fixes.
squash eddbe50 Stylefixes for flake8.
squash 6664775 Minor fixes and docstrings for RetryingClient.
squash cf2b44d Add unit-tests for RetryingClient.
squash f08d348 Add RetryingClient example to the getting started docuementation.
squash 71f81bb More robust import of Iterable.
squash b0782c5 0 index retry range.
squash 03d7c48 Reorder imports of tests for pop8ness.
squash eee78cc Sharpen test-case.
squash 5da4090 Simplify argument parsing.

All these changes are related to a single one feature.

Plan was to squash just before merging, since the commits give context to some of the comments in the PR.

Edit:
Thanks for all the feedback btw. :)

Thanks to you too :)

No problem it make sense to squash it just before.

@4383 4383 mentioned this pull request Jul 8, 2021
@martinnj
Copy link
Contributor Author

@cgordon Hate to be pushy, but any news on this one? :)

Copy link
Collaborator

@cgordon cgordon left a comment

Choose a reason for hiding this comment

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

LGTM! I left one comment that you can do, or not, at your discretion.

pymemcache/client/retrying.py Show resolved Hide resolved
@cgordon
Copy link
Collaborator

cgordon commented Jul 12, 2021

Hmm, I hit "Comment" instead of "Approve" by accident, anyone know how to navigate this UI to approve this PR?

@martinnj martinnj force-pushed the feature/retrying-client branch from 52e0238 to 75fe5c8 Compare July 13, 2021 05:40
@martinnj martinnj requested a review from cgordon July 13, 2021 05:43
@martinnj
Copy link
Contributor Author

martinnj commented Jul 13, 2021

Hmm, I hit "Comment" instead of "Approve" by accident, anyone know how to navigate this UI to approve this PR?

@cgordon Good question. No clue. I've hit "Re-request review" for the blocking changes, might give you a prompt to clear it. :)

@cgordon cgordon merged commit db3b18c into pinterest:master Jul 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants