blob: f92b6e6427612480ab215ca34905043dcdad3ef5 [file] [log] [blame]
Max Rasskazovc018e382015-06-03 15:22:04 +03001#-*- coding: utf-8 -*-
2
3
4import logging
5import os
6import time
7
8
9logging.basicConfig()
10logger = logging.getLogger('safe_rsync')
11
12loglevel = os.environ.get('LOGLEVEL', 'INFO')
13if loglevel not in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'):
14 logger.warn('LOGLEVEL environment variable has wrong value=={}. Using '
15 '"INFO" by default.'.format(loglevel))
16 loglevel = 'INFO'
17logger.setLevel(loglevel)
18
19
20def logged(logger=None):
21 if logger is None:
22 logger = globals().get('logger')
23
24 def wrap(f):
25 def wrapped_f(*args, **kwargs):
26 logger.debug('Starting {}({}, {}) (defaults: {})'
27 ''.format(f.__name__,
28 str(args),
29 str(kwargs),
30 str(f.__defaults__))
31 )
32 r = f(*args, **kwargs)
33 logger.debug('{} done with result "{}".'.
34 format(f.__name__, str(r)))
35 return r
36 return wrapped_f
37 return wrap
38
39
40# retry decorator
41def retry(expected_status, timeout=None, attempts=None):
42
43 def wrap(f):
44 def wrapped_f(*args, **kwargs):
45 r = f(*args, **kwargs)
46 return r
47 return wrapped_f
48 return wrap
49
50
51class ResultNotProduced(Exception):
52 def __init__(self, value):
53 self.value = value
54
55 def __str__(self):
56 return repr(self.value)
57
58
59class Retry(object):
60 """
61 Waits while the function reaches the specified status.
62
63 :param function: function that returns some status
64 :param expected_status: status the machine should turn to
65 :param attempts: how many times to check status
66 :param timeout: timeout in seconds before attempts
67 :return: True if node moves to the specified status, False otherwise
68 :Examples:
69 Retry(timeout=3, attempts=10).wait(function, result, param1, param2)
70 Retry().wait_result(function, result, param1, param2)
71 """
72
73 def __init__(self, timeout=5, attempts=10):
74 self.timeout = timeout
75 self.attempts = attempts
76 self.logger = globals().get('logger').getChild('Retry')
77
78 def wait_result(self, function, expected_result, *args, **kwargs):
79
80 self.logger.debug('Wait for {}() == {}...'
81 ''.format(function.__name__, str(expected_result)))
82
83 @logged(self.logger)
84 def f():
85 return function(*args, **kwargs)
86
87 attempt = 1
88 while attempt <= self.attempts:
89 try:
90 result = f()
91 except Exception as e:
92 self.logger.error('Exception on function {}: {}'
93 ''.format(function.__name__, str(e)))
94 raise
95 else:
96 if result == expected_result:
97 self.logger.debug('Got on attempt #{}:'.format(attempt))
98 return result
99 attempt += 1
100 time.sleep(self.timeout)
101
102 raise ResultNotProduced('Result "{}" was not produced during '
103 '{} attempts.'
104 ''.format(expected_result, attempt - 1))