summaryrefslogtreecommitdiff
path: root/lib/ansible/module_utils/api.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/module_utils/api.py')
-rw-r--r--lib/ansible/module_utils/api.py15
1 files changed, 14 insertions, 1 deletions
diff --git a/lib/ansible/module_utils/api.py b/lib/ansible/module_utils/api.py
index e780ec6b50..2de8a4efc1 100644
--- a/lib/ansible/module_utils/api.py
+++ b/lib/ansible/module_utils/api.py
@@ -26,11 +26,15 @@ The 'api' module provides the following common argument specs:
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
+import copy
import functools
+import itertools
import random
import sys
import time
+import ansible.module_utils.compat.typing as t
+
def rate_limit_argument_spec(spec=None):
"""Creates an argument spec for working with rate limiting"""
@@ -141,6 +145,15 @@ def retry_with_delays_and_condition(backoff_iterator, should_retry_error=None):
:param backoff_iterator: An iterable of delays in seconds.
:param should_retry_error: A callable that takes an exception of the decorated function and decides whether to retry or not (returns a bool).
"""
+ def _emit_isolated_iterator_copies(original_iterator): # type: (t.Iterable[t.Any]) -> t.Generator
+ # Ref: https://stackoverflow.com/a/30232619/595220
+ _copiable_iterator, _first_iterator_copy = itertools.tee(original_iterator)
+ yield _first_iterator_copy
+ while True:
+ yield copy.copy(_copiable_iterator)
+ backoff_iterator_generator = _emit_isolated_iterator_copies(backoff_iterator)
+ del backoff_iterator # prevent accidental use elsewhere
+
if should_retry_error is None:
should_retry_error = retry_never
@@ -152,7 +165,7 @@ def retry_with_delays_and_condition(backoff_iterator, should_retry_error=None):
"""
call_retryable_function = functools.partial(function, *args, **kwargs)
- for delay in backoff_iterator:
+ for delay in next(backoff_iterator_generator):
try:
return call_retryable_function()
except Exception as e: