{"id":953,"date":"2017-10-21T22:08:38","date_gmt":"2017-10-21T14:08:38","guid":{"rendered":"http:\/\/192.168.1.20\/?p=953"},"modified":"2017-10-23T11:51:45","modified_gmt":"2017-10-23T03:51:45","slug":"python-{d4daabd1ba368d9860c36387ddb72bbda14f8f9559d69d60a952800885260c03}e9{d4daabd1ba368d9860c36387ddb72bbda14f8f9559d69d60a952800885260c03}94{47dd41ec6bdcbd9a214c783a3735392b82ea6d1d918378c5a53e0640","status":"publish","type":"post","link":"http:\/\/alextop.top\/?p=953","title":{"rendered":"python \u9519\u8bef\u91cd\u8bd5\u6a21\u5757tenacity"},"content":{"rendered":"<p>\u4ee5\u524d\u53ebretrying\uff0c\u4ee5\u88c5\u9970\u5668\u5f62\u5f0f\u4f5c\u7528\u4e0e\u51fd\u6570<\/p>\n<p>\u57fa\u672c\u7528\u6cd5<br \/>\n\u57fa\u672c\u7528\u6cd5\u662f\u5c06\u5176\u7528\u4f5c\u88c5\u9970\u5668\uff1a<br \/>\nimport tenacity<\/p>\n<p>@ tenacity.retry<br \/>\ndef do_something_and_retry_on_any_exception():<br \/>\npass<\/p>\n<p>\u8fd9\u5c06\u4f7f\u8be5\u51fd\u6570do_something_and_retry_on_any_exception\u4e00\u904d\u53c8\u4e00\u904d\u5730\u88ab\u8c03\u7528\uff0c\u76f4\u5230\u5b83\u505c\u6b62\u5f15\u53d1\u5f02\u5e38\u3002\u5f88\u96be\u8bbe\u8ba1\u51fa\u66f4\u7b80\u5355\u7684\u4e1c\u897f\u3002\u663e\u7136\uff0c\u8fd9\u662f\u4e00\u4e2a\u975e\u5e38\u7f55\u89c1\u7684\u60c5\u51b5\uff0c\u56e0\u4e3a\u901a\u5e38\u60f3\u8981\u7b49\u5f85\u4e00\u6bb5\u65f6\u95f4\u7684\u91cd\u8bd5&#8230;&#8230;\u5176\u5b9e\u5176\u4ed6\u7684\u7528\u6cd5\u6211\u662f\u770b\u4e0d\u61c2&#8230;.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>retrying\u539f\u7f51\u5740\uff1ahttps:\/\/julien.danjou.info\/blog\/2015\/python-retrying<\/p>\n<p>tenacity\u539f\u7f51\u5740\uff1ahttps:\/\/julien.danjou.info\/blog\/2017\/python-tenacity<\/p>\n<p>\u539f\u6587\u5982\u4e0b<\/p>\n<p>A couple of years ago, I\u00a0<a href=\"https:\/\/julien.danjou.info\/blog\/2015\/python-retrying\">wrote about the Python\u00a0<em>retrying<\/em>\u00a0library<\/a>. This library was designed to retry the execution of a task when a failure occurred.<\/p>\n<p>I started to spread usage of this library in various projects, such as\u00a0<a href=\"http:\/\/gnocchi.xyz\/\">Gnocchi<\/a>, these last years. Unfortunately, it started to get very hard to contribute and send patches to the upstream\u00a0<em>retrying<\/em>\u00a0project. I spent several months trying to work with the original author. But after a while, I had to come to the conclusion that I would be unable to fix bugs and enhance it at the pace I would like to. Therefore, I had to take a difficult decision and decided to fork the library.<\/p>\n<h1>Here comes\u00a0<em>tenacity<\/em><\/h1>\n<p>I picked a new name and rewrote parts of the API of\u00a0<em>retrying<\/em>\u00a0that were not working correctly or were too complicated. I also fixed bugs with the help of Joshua, and named this new library\u00a0<em>tenacity<\/em>. It works in the same manner as\u00a0<em>retrying<\/em>\u00a0does, except that it is written in a more functional way and offers some nifty new features.<\/p>\n<h1>Basic usage<\/h1>\n<p>The basic usage is to use it as a decorator:<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">tenacity<\/span>\r\n\u00a0\r\n<span class=\"nd\">@tenacity.retry<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">do_something_and_retry_on_any_exception<\/span><span class=\"p\">():<\/span>\r\n    <span class=\"k\">pass<\/span><\/pre>\n<\/div>\n<p>This will make the function\u00a0<code>do_something_and_retry_on_any_exception<\/code>\u00a0be called over and over again until it stops raising an exception. It would have been hard to design anything simpler. Obviously, this is a pretty rare case, as one usually wants to e.g. wait some time between retries. For that,\u00a0<em>tenacity<\/em>\u00a0offers a large panel of waiting methods:<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">tenacity<\/span>\r\n\u00a0\r\n<span class=\"nd\">@tenacity.retry<\/span><span class=\"p\">(<\/span><span class=\"n\">wait<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">wait_fixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">))<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">do_something_and_retry<\/span><span class=\"p\">():<\/span>\r\n    <span class=\"n\">do_something<\/span><span class=\"p\">()<\/span><\/pre>\n<\/div>\n<p>Or a simple exponential back-off method can be used instead:<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">tenacity<\/span>\r\n\u00a0\r\n<span class=\"nd\">@tenacity.retry<\/span><span class=\"p\">(<\/span><span class=\"n\">wait<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">wait_exponential<\/span><span class=\"p\">())<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">do_something_and_retry<\/span><span class=\"p\">():<\/span>\r\n    <span class=\"n\">do_something<\/span><span class=\"p\">()<\/span><\/pre>\n<\/div>\n<h1>Combination<\/h1>\n<p>What is especially interesting with\u00a0<em>tenacity<\/em>, is that you can easily combine several methods. For example, you can combine\u00a0<code>tenacity.wait.wait_random<\/code>\u00a0with\u00a0<code>tenacity.wait.wait_fixed<\/code>\u00a0to wait a number of seconds defined in an interval:<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">tenacity<\/span>\r\n\u00a0\r\n<span class=\"nd\">@tenacity.retry<\/span><span class=\"p\">(<\/span><span class=\"n\">wait<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">wait_fixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"n\">wait<\/span><span class=\"o\">.<\/span><span class=\"n\">wait_random<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">))<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">do_something_and_retry<\/span><span class=\"p\">():<\/span>\r\n    <span class=\"n\">do_something<\/span><span class=\"p\">()<\/span><\/pre>\n<\/div>\n<p>This will make the function being retried wait randomly between 10 and 13 seconds before trying again.<\/p>\n<p><em>tenacity<\/em>\u00a0offers more customization, such as retrying on some exceptions only. You can retry every second to execute the function only if the exception raised by\u00a0<code>do_something<\/code>\u00a0is an instance of\u00a0<code>IOError<\/code>, e.g. a network communication error.<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">tenacity<\/span>\r\n\u00a0\r\n<span class=\"nd\">@tenacity.retry<\/span><span class=\"p\">(<\/span><span class=\"n\">wait<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">wait_fixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">),<\/span>\r\n                <span class=\"n\">retry<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">retry_if_exception_type<\/span><span class=\"p\">(<\/span><span class=\"ne\">IOError<\/span><span class=\"p\">))<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">do_something_and_retry<\/span><span class=\"p\">():<\/span>\r\n    <span class=\"n\">do_something<\/span><span class=\"p\">()<\/span><\/pre>\n<\/div>\n<p>You can combine several condition easily by using the\u00a0<code>|<\/code>\u00a0or\u00a0<code>&amp;<\/code>\u00a0binary operators. They are used to make the code retry if an\u00a0<code>IOError<\/code>exception is raised, or if no result is returned. Also, a stop condition is added with the\u00a0<code>stop<\/code>\u00a0keyword arguments. It allows to specify a condition unrelated to the function result of exception to stop, such as a number of attemps or a delay.<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">tenacity<\/span>\r\n\u00a0\r\n<span class=\"nd\">@tenacity.retry<\/span><span class=\"p\">(<\/span><span class=\"n\">wait<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">wait_fixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">),<\/span>\r\n                <span class=\"n\">stop<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">stop_after_delay<\/span><span class=\"p\">(<\/span><span class=\"mi\">60<\/span><span class=\"p\">),<\/span>\r\n                <span class=\"n\">retry<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">retry_if_exception_type<\/span><span class=\"p\">(<\/span><span class=\"ne\">IOError<\/span><span class=\"p\">)<\/span> <span class=\"o\">|<\/span>\r\n                       <span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">retry_if_result<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">result<\/span><span class=\"p\">:<\/span> <span class=\"n\">result<\/span> <span class=\"o\">==<\/span> <span class=\"bp\">None<\/span><span class=\"p\">))<\/span>\r\n<span class=\"k\">def<\/span> <span class=\"nf\">do_something_and_retry<\/span><span class=\"p\">():<\/span>\r\n    <span class=\"n\">do_something<\/span><span class=\"p\">()<\/span><\/pre>\n<\/div>\n<p>The functional approach of\u00a0<em>tenacity<\/em>\u00a0makes it easy and clean to combine a lot of condition for various use cases with simple binary operators.<\/p>\n<h1>Standalone usage<\/h1>\n<p><em>tenacity<\/em>\u00a0can also be used without decorator by using the object\u00a0<code>Retrying<\/code>, that implements its main behaviour, and usig its\u00a0<code>call<\/code>method. This allows to call any function with different retry conditions, or to retry any piece of code that do not use the decorator at all \u2013 like code from an external library.<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kn\">import<\/span> <span class=\"nn\">tenacity<\/span>\r\n\u00a0\r\n<span class=\"n\">r<\/span> <span class=\"o\">=<\/span> <span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">Retrying<\/span><span class=\"p\">(<\/span>\r\n    <span class=\"n\">wait<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">wait_fixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">),<\/span>\r\n    <span class=\"n\">retry<\/span><span class=\"o\">=<\/span><span class=\"n\">tenacity<\/span><span class=\"o\">.<\/span><span class=\"n\">retry_if_exception_type<\/span><span class=\"p\">(<\/span><span class=\"ne\">IOError<\/span><span class=\"p\">))<\/span>\r\n<span class=\"n\">r<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">(<\/span><span class=\"n\">do_something<\/span><span class=\"p\">)<\/span><\/pre>\n<\/div>\n<p>This also allows you to re-use that object without creating one new each time, saving some memory!<\/p>\n<p>I hope you&#8217;ll like it and will find it some use. Feel free to fork it, report bug or ask for new features on\u00a0<a href=\"https:\/\/github.com\/jd\/tenacity\">its GitHub<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4ee5\u524d\u53ebretrying\uff0c\u4ee5\u88c5\u9970&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,10],"tags":[],"class_list":["post-953","post","type-post","status-publish","format-standard","hentry","category-python","category-jishu"],"_links":{"self":[{"href":"http:\/\/alextop.top\/index.php?rest_route=\/wp\/v2\/posts\/953"}],"collection":[{"href":"http:\/\/alextop.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/alextop.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/alextop.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/alextop.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=953"}],"version-history":[{"count":1,"href":"http:\/\/alextop.top\/index.php?rest_route=\/wp\/v2\/posts\/953\/revisions"}],"predecessor-version":[{"id":957,"href":"http:\/\/alextop.top\/index.php?rest_route=\/wp\/v2\/posts\/953\/revisions\/957"}],"wp:attachment":[{"href":"http:\/\/alextop.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/alextop.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=953"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/alextop.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}