From ff688f5d5d04954357594d24baf0ef9f8fe557f4 Mon Sep 17 00:00:00 2001 From: Marc Billow Date: Sun, 5 Jul 2026 16:51:17 -0500 Subject: [PATCH] fix: residual inter-request pacing instead of blind full-interval sleep pace() slept the entire rate-limit interval every call regardless of how much of it had already elapsed since the last real send (e.g. spent processing the previous block's response). Track the last send timestamp and only sleep the remainder, recovering time already spent between requests without changing the enforced minimum interval. Verified against 10.0.0.129/10.0.0.254: multi-block /device/0 fetches still complete cleanly, faster per sweep, with the same request spacing guarantee (patch and measurement from QuiteYellow, PR #8 review). --- protocol/dtls_session.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/protocol/dtls_session.py b/protocol/dtls_session.py index 7ada48a..157c295 100644 --- a/protocol/dtls_session.py +++ b/protocol/dtls_session.py @@ -113,10 +113,14 @@ class DtlsCoapSession: self._stop = threading.Event() self._reader_thread = None + self._last_send_ts = 0.0 def pace(self) -> None: - """Sleep one rate-limit interval. Uses _stop so session teardown wakes it.""" - self._stop.wait(self._min_req_interval) + """Sleep only the part of the rate-limit interval not already consumed + since the last real send. Uses _stop so session teardown wakes it.""" + remaining = self._min_req_interval - (time.monotonic() - self._last_send_ts) + if remaining > 0: + self._stop.wait(remaining) # ---- lifecycle --------------------------------------------------- @@ -273,6 +277,7 @@ class DtlsCoapSession: raise ConnectionError("DTLS session closed") try: self.conn.send(datagram) + self._last_send_ts = time.monotonic() while True: o = self.conn.bio_read(65535) if not o: