deb-heat/heat/common/timeutils.py
Rabi Mishra 8b6e1eac1d Refactor timeout calculation to utility
Change-Id: I8d846a2c99a9bd88bbff8115646f238a6244de8a
2015-07-18 08:51:59 +05:30

83 lines
2.5 KiB
Python

#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Utilities for handling ISO 8601 duration format.
"""
import random
import re
import time
from heat.common.i18n import _
iso_duration_re = re.compile('PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$')
wallclock = time.time
class Duration(object):
'''
Note that we don't attempt to handle leap seconds or large clock
jumps here. The latter are assumed to be rare and the former
negligible in the context of the timeout. Time zone adjustments,
Daylight Savings and the like *are* handled. PEP 418 adds a proper
monotonic clock, but only in Python 3.3.
'''
def __init__(self, timeout=0):
self._endtime = wallclock() + timeout
def expired(self):
return wallclock() > self._endtime
def endtime(self):
return self._endtime
def parse_isoduration(duration):
"""
Convert duration in ISO 8601 format to second(s).
Year, Month, Week, and Day designators are not supported.
Example: 'PT12H30M5S'
"""
result = iso_duration_re.match(duration)
if not result:
raise ValueError(_('Only ISO 8601 duration format of the form '
'PT#H#M#S is supported.'))
t = 0
t += (3600 * int(result.group(1))) if result.group(1) else 0
t += (60 * int(result.group(2))) if result.group(2) else 0
t += int(result.group(3)) if result.group(3) else 0
return t
def retry_backoff_delay(attempt, scale_factor=1.0, jitter_max=0.0):
"""
Calculate an exponential backoff delay with jitter.
Delay is calculated as
2^attempt + (uniform random from [0,1) * jitter_max)
:param attempt: The count of the current retry attempt
:param scale_factor: Multiplier to scale the exponential delay by
:param jitter_max: Maximum of random seconds to add to the delay
:returns: Seconds since epoch to wait until
"""
exp = float(2 ** attempt) * float(scale_factor)
if jitter_max == 0.0:
return exp
return exp + random.random() * jitter_max