From 2d2ff221926bb11bfe5d544dc1fbd558fab89f10 Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Mon, 15 Nov 2021 15:19:40 -0500
Subject: [PATCH] pick the right share to use for lease renewal decisions

now that the server actually returns different info for different shares, we
can, and we should, and we must
---
 src/_zkapauthorizer/lease_maintenance.py | 25 +++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/src/_zkapauthorizer/lease_maintenance.py b/src/_zkapauthorizer/lease_maintenance.py
index 8858c91..e8e76cd 100644
--- a/src/_zkapauthorizer/lease_maintenance.py
+++ b/src/_zkapauthorizer/lease_maintenance.py
@@ -206,12 +206,31 @@ def renew_leases_on_server(
         # Keep track of what's been seen.
         activity.observe([stat.size for stat in stat_dict.values()])
 
-        # All shares have the same lease information.
-        stat = stat_dict.popitem()[1]
-        if needs_lease_renew(min_lease_remaining, stat, now):
+        # Each share has its own leases and each lease has its own expiration
+        # time.  For each share the server only returns the lease with the
+        # expiration time farthest in the future.
+        #
+        # There is no API for renewing leases on just *some* shares!  It is
+        # all or nothing.  So from the server's response we find the share
+        # that will have no active lease soonest and make our decision about
+        # whether to renew leases at this storage index or not based on that.
+        most_endangered = soonest_expiration(stat_dict.values())
+        if needs_lease_renew(min_lease_remaining, most_endangered, now):
             yield renew_lease(renewal_secret, cancel_secret, storage_index, server)
 
 
+def soonest_expiration(stats):
+    # type: (Iterable[ShareStat]) -> ShareStat
+    """
+    :return: The share stat from ``stats`` all the leases of which will expire
+        soonest.
+    """
+    return min(
+        stats,
+        key=lambda stat: stat.lease_expiration,
+    )
+
+
 def renew_lease(renewal_secret, cancel_secret, storage_index, server):
     """
     Renew the lease on the shares in one storage index on one server.
-- 
GitLab