diff --git a/src/_zkapauthorizer/lease_maintenance.py b/src/_zkapauthorizer/lease_maintenance.py index 2f40458691260d110c69f92477b222299bddceee..e7e0bb3c3d53cf64b89e865692c372323b031924 100644 --- a/src/_zkapauthorizer/lease_maintenance.py +++ b/src/_zkapauthorizer/lease_maintenance.py @@ -260,11 +260,16 @@ class _FuzzyTimerService(Service): def startService(self): Service.startService(self) - self.reactor.callLater( + self._call = self.reactor.callLater( self.initial_interval.total_seconds(), self._iterate, ) + def stopService(self): + self._call.cancel() + self._call = None + return Service.stopService(self) + def _iterate(self): """ Run the operation once and then schedule it to run again. diff --git a/src/_zkapauthorizer/tests/test_lease_maintenance.py b/src/_zkapauthorizer/tests/test_lease_maintenance.py index 5edf640aee95e8177b9a0614ede5a4a9e1daf391..add7d18c30395108d56826e9d8799cd4a774f898 100644 --- a/src/_zkapauthorizer/tests/test_lease_maintenance.py +++ b/src/_zkapauthorizer/tests/test_lease_maintenance.py @@ -32,6 +32,7 @@ from testtools import ( TestCase, ) from testtools.matchers import ( + Is, Equals, Always, HasLength, @@ -69,6 +70,7 @@ from twisted.internet.task import ( ) from twisted.internet.defer import ( succeed, + maybeDeferred, ) from twisted.application.service import ( IService, @@ -307,6 +309,34 @@ class LeaseMaintenanceServiceTests(TestCase): between(low, high), ) + @given( + randoms(), + clocks(), + ) + def test_clean_up_when_stopped(self, random, clock): + """ + When the service is stopped, the delayed call in the reactor is removed. + """ + service = lease_maintenance_service( + lambda: None, + clock, + FilePath(self.useFixture(TempDir()).join(u"last-run")), + random, + ) + service.startService() + self.assertThat( + maybeDeferred(service.stopService), + succeeded(Is(None)), + ) + self.assertThat( + clock.getDelayedCalls(), + Equals([]), + ) + self.assertThat( + service.running, + Equals(False), + ) + @given( randoms(), clocks(),