Skip to content

Commit

Permalink
Deadline to use a monotonic timer
Browse files Browse the repository at this point in the history
  • Loading branch information
crusaderky committed Mar 21, 2024
1 parent 8927bfd commit 671f4a8
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 28 deletions.
19 changes: 8 additions & 11 deletions distributed/tests/test_deadline.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,29 @@


def test_deadline():
before_start = time()
deadline = Deadline.after(5)
after_start = time()

assert deadline.duration == 5
assert deadline.expired is False
assert deadline.expires is True
assert deadline.expires_at - deadline.started_at == 5
assert deadline.expires_at_mono - deadline.started_at_mono == 5
assert 4 < deadline.expires_at - deadline.started_at < 6
assert 0 <= deadline.elapsed <= 1
assert 4 <= deadline.remaining <= 5

deadline2 = Deadline(deadline.expires_at)

assert deadline.expires_at == deadline2.expires_at


def test_infinite_deadline():
deadline = Deadline(None)

assert deadline.expires_at_mono is None
assert deadline.expires_at is None
assert deadline.expired is False
assert deadline.expires is False
assert deadline.expires_at is None
assert deadline.remaining is None
assert deadline.duration is None
assert 0 <= deadline.elapsed <= 1

deadline2 = Deadline.after(None)

assert deadline2.expires_at is None
assert deadline2.expires_at_mono is None


@gen_test()
Expand Down
55 changes: 38 additions & 17 deletions distributed/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1841,52 +1841,73 @@ def is_python_shutting_down() -> bool:
class Deadline:
"""Utility class tracking a deadline and the progress toward it"""

#: Expiry time of the deadline in seconds since the epoch
#: Expiry time of the deadline in seconds since the start of the monotonic timer
#: or None if the deadline never expires
expires_at: float | None
expires_at_mono: float | None

Check warning on line 1846 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1846

Added line #L1846 was not covered by tests
#: Seconds since the epoch when the deadline was created
started_at_mono: float

Check warning on line 1848 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1848

Added line #L1848 was not covered by tests
#: Seconds since the start of the monotonic timer when the deadline was created
started_at: float

__slots__ = tuple(__annotations__)

Check warning on line 1852 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1852

Added line #L1852 was not covered by tests

def __init__(self, expires_at: float | None = None):
self.expires_at = expires_at
self.started_at = time()
self.started_at_mono = monotonic()
if expires_at is not None:
self.expires_at_mono = expires_at - self.started_at + self.started_at_mono

Check warning on line 1858 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1856-L1858

Added lines #L1856 - L1858 were not covered by tests
else:
self.expires_at_mono = None

Check warning on line 1860 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1860

Added line #L1860 was not covered by tests

@classmethod
def after(cls, duration: float | None = None) -> Deadline:
"""Create a new ``Deadline`` that expires in ``duration`` seconds
or never if ``duration`` is None"""
started_at = time()
expires_at = duration + started_at if duration is not None else duration
deadline = cls(expires_at)
deadline.started_at = started_at
return deadline
or never if ``duration`` is None
"""
inst = cls()
if duration is not None:
inst.expires_at_mono = inst.started_at_mono + duration
return inst

Check warning on line 1870 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1867-L1870

Added lines #L1867 - L1870 were not covered by tests

@property
def expires_at(self) -> float | None:

Check warning on line 1873 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1872-L1873

Added lines #L1872 - L1873 were not covered by tests
"""Expiry time of the deadline in seconds since the unix epoch
or None if the deadline never expires.
Note that this can change over time if the wall clock is adjusted by the OS.
"""
if self.expires_at_mono is None:
return None
return self.expires_at_mono - monotonic() + time()

Check warning on line 1881 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1879-L1881

Added lines #L1879 - L1881 were not covered by tests

@property
def duration(self) -> float | None:
"""Seconds between the creation and expiration time of the deadline
if the deadline expires, None otherwise"""
if self.expires_at is None:
if the deadline expires, None otherwise
"""
if (exp := self.expires_at_mono) is None:

Check warning on line 1888 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1888

Added line #L1888 was not covered by tests
return None
return self.expires_at - self.started_at
return exp - self.started_at_mono

Check warning on line 1890 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1890

Added line #L1890 was not covered by tests

@property
def expires(self) -> bool:
"""Whether the deadline ever expires"""
return self.expires_at is not None
return self.expires_at_mono is not None

Check warning on line 1895 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1895

Added line #L1895 was not covered by tests

@property
def elapsed(self) -> float:
"""Seconds that elapsed since the deadline was created"""
return time() - self.started_at
return monotonic() - self.started_at_mono

Check warning on line 1900 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1900

Added line #L1900 was not covered by tests

@property
def remaining(self) -> float | None:
"""Seconds remaining until the deadline expires if an expiry time is set,
None otherwise"""
if self.expires_at is None:
None otherwise
"""
if (exp := self.expires_at_mono) is None:

Check warning on line 1907 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1907

Added line #L1907 was not covered by tests
return None
else:
return max(0, self.expires_at - time())
return max(0, exp - monotonic())

Check warning on line 1910 in distributed/utils.py

View check run for this annotation

Codecov / codecov/patch

distributed/utils.py#L1910

Added line #L1910 was not covered by tests

@property
def expired(self) -> bool:
Expand Down

0 comments on commit 671f4a8

Please sign in to comment.