Skip to content

Commit

Permalink
fix(core): prefer use of time.monotonic
Browse files Browse the repository at this point in the history
`time.time()` is subject to change sin system local time and can trigger unexpected behaviour. Prefer the use of `time.monotonic` instead of `time.time` since we are not making use of the actual time, only an amount of time elapsed.

Fixes #722
  • Loading branch information
StephenSorriaux committed Feb 7, 2024
1 parent 144b696 commit b00d88f
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 15 deletions.
4 changes: 2 additions & 2 deletions kazoo/handlers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,11 @@ def create_tcp_connection(
# this ugliness...
timeout = module.getdefaulttimeout()
if timeout is not None:
end = time.time() + timeout
end = time.monotonic() + timeout
sock = None

while True:
timeout_at = end if end is None else end - time.time()
timeout_at = end if end is None else end - time.monotonic()
# The condition is not '< 0' here because socket.settimeout treats 0 as
# a special case to put the socket in non-blocking mode.
if timeout_at is not None and timeout_at <= 0:
Expand Down
18 changes: 9 additions & 9 deletions kazoo/protocol/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,19 @@ def __init__(self, hosts, connection_func, socket_handling):

def __iter__(self):
if not self.last_attempt:
self.last_attempt = time.time()
self.last_attempt = time.monotonic()
delay = 0.5
while True:
yield self._next_server(delay)

def _next_server(self, delay):
jitter = random.randint(0, 100) / 100.0
while time.time() < self.last_attempt + delay + jitter:
while time.monotonic() < self.last_attempt + delay + jitter:
# Skip rw ping checks if its too soon
return False
for host, port in self.hosts:
log.debug("Pinging server for r/w: %s:%s", host, port)
self.last_attempt = time.time()
self.last_attempt = time.monotonic()
try:
with self.socket_handling():
sock = self.connection((host, port))
Expand All @@ -136,7 +136,7 @@ def _next_server(self, delay):
return False

# Add some jitter between host pings
while time.time() < self.last_attempt + jitter:
while time.monotonic() < self.last_attempt + jitter:
return False
delay *= 2

Expand Down Expand Up @@ -617,14 +617,14 @@ def _connect_attempt(self, host, hostip, port, retry):
connect_timeout = connect_timeout / 1000.0
retry.reset()
self.ping_outstanding.clear()
last_send = time.time()
last_send = time.monotonic()
with self._socket_error_handling():
while not self.client._stopped.is_set():
# Watch for something to read or send
jitter_time = random.randint(1, 40) / 100.0
deadline = last_send + read_timeout / 2.0 - jitter_time
# Ensure our timeout is positive
timeout = max([deadline - time.time(), jitter_time])
timeout = max([deadline - time.monotonic(), jitter_time])
s = self.handler.select(
[self._socket, self._read_sock], [], [], timeout
)[0]
Expand All @@ -646,12 +646,12 @@ def _connect_attempt(self, host, hostip, port, retry):
if self._read_sock in s:
self._send_request(read_timeout, connect_timeout)
# Requests act as implicit pings.
last_send = time.time()
last_send = time.monotonic()
continue

if time.time() >= deadline:
if time.monotonic() >= deadline:
self._send_ping(connect_timeout)
last_send = time.time()
last_send = time.monotonic()
self.logger.info("Closing connection to %s:%s", host, port)
client._session_callback(KeeperState.CLOSED)
return STOP_CONNECTING
Expand Down
2 changes: 1 addition & 1 deletion kazoo/recipe/watchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,4 +449,4 @@ def _inner_start(self):

def _children_watcher(self, async_result, event):
self.children_changed.set()
async_result.set(time.time())
async_result.set(time.monotonic())
4 changes: 2 additions & 2 deletions kazoo/retry.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def __call__(self, func, *args, **kwargs):
while True:
try:
if self.deadline is not None and self._cur_stoptime is None:
self._cur_stoptime = time.time() + self.deadline
self._cur_stoptime = time.monotonic() + self.deadline
return func(*args, **kwargs)
except ConnectionClosedError:
raise
Expand All @@ -144,7 +144,7 @@ def __call__(self, func, *args, **kwargs):

if (
self._cur_stoptime is not None
and time.time() + sleeptime >= self._cur_stoptime
and time.monotonic() + sleeptime >= self._cur_stoptime
):
raise RetryFailedError("Exceeded retry deadline")

Expand Down
2 changes: 1 addition & 1 deletion kazoo/tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def __init__(
timeout=None,
wait=None,
exception=None,
getnow=(lambda: time.time),
getnow=(lambda: time.monotonic),
getsleep=(lambda: time.sleep),
):
if timeout is not None:
Expand Down

0 comments on commit b00d88f

Please sign in to comment.