Browse Source

[tasks] Handle loop functions running multiple times due to clock drift

pull/7680/head
Rapptz 3 years ago
parent
commit
64c6639f4b
  1. 22
      discord/ext/tasks/__init__.py

22
discord/ext/tasks/__init__.py

@ -26,6 +26,7 @@ from __future__ import annotations
import asyncio
import datetime
import logging
from typing import (
Any,
Awaitable,
@ -48,6 +49,8 @@ from collections.abc import Sequence
from discord.backoff import ExponentialBackoff
from discord.utils import MISSING
_log = logging.getLogger(__name__)
# fmt: off
__all__ = (
'loop',
@ -173,6 +176,25 @@ class Loop(Generic[LF]):
if not self._last_iteration_failed:
self._last_iteration = self._next_iteration
self._next_iteration = self._get_next_sleep_time()
# In order to account for clock drift, we need to ensure that
# the next iteration always follows the last iteration.
# Sometimes asyncio is cheeky and wakes up a few microseconds before our target
# time, causing it to repeat a run.
while self._next_iteration <= self._last_iteration:
_log.warn(
(
'Clock drift detected for task %s. Woke up at %s but needed to sleep until %s. '
'Sleeping until %s again to correct clock'
),
self.coro.__qualname__,
discord.utils.utcnow(),
self._next_iteration,
self._next_iteration,
)
await self._try_sleep_until(self._next_iteration)
self._next_iteration = self._get_next_sleep_time()
try:
await self.coro(*args, **kwargs)
self._last_iteration_failed = False

Loading…
Cancel
Save