diff --git a/src/KubernetesClient/LeaderElection/LeaderElector.cs b/src/KubernetesClient/LeaderElection/LeaderElector.cs index d78a967ba..dce925d5a 100644 --- a/src/KubernetesClient/LeaderElection/LeaderElector.cs +++ b/src/KubernetesClient/LeaderElection/LeaderElector.cs @@ -49,7 +49,12 @@ public string GetLeader() return observedRecord?.HolderIdentity; } - public async Task RunAsync(CancellationToken cancellationToken = default) + /// + /// Tries to acquire and hold leadership once via a Kubernetes Lease resource. + /// Will complete the returned Task and not retry to acquire leadership again after leadership is lost once. + /// + /// A token to cancel the operation. + public async Task RunUntilLeadershipLostAsync(CancellationToken cancellationToken = default) { await AcquireAsync(cancellationToken).ConfigureAwait(false); @@ -107,6 +112,32 @@ public async Task RunAsync(CancellationToken cancellationToken = default) } } + /// + /// Tries to acquire leadership via a Kubernetes Lease resource. + /// Will retry to acquire leadership again after leadership was lost. + /// + /// A Task which completes only on cancellation + /// A token to cancel the operation. + public async Task RunAndTryToHoldLeadershipForeverAsync(CancellationToken cancellationToken = default) + { + while (!cancellationToken.IsCancellationRequested) + { + await RunUntilLeadershipLostAsync(cancellationToken).ConfigureAwait(false); + } + } + + /// + /// Tries to acquire leadership once via a Kubernetes Lease resource. + /// Will complete the returned Task and not retry to acquire leadership again after leadership is lost once. + /// + /// + /// A token to cancel the operation. + [Obsolete("Replaced by RunUntilLeadershipLostAsync to encode behavior in method name.")] + public Task RunAsync(CancellationToken cancellationToken = default) + { + return RunUntilLeadershipLostAsync(cancellationToken); + } + private async Task TryAcquireOrRenew(CancellationToken cancellationToken) { var l = config.Lock; diff --git a/tests/KubernetesClient.Tests/LeaderElection/LeaderElectionTests.cs b/tests/KubernetesClient.Tests/LeaderElection/LeaderElectionTests.cs index 1e65f8dfb..22cb12412 100644 --- a/tests/KubernetesClient.Tests/LeaderElection/LeaderElectionTests.cs +++ b/tests/KubernetesClient.Tests/LeaderElection/LeaderElectionTests.cs @@ -71,7 +71,7 @@ public void SimpleLeaderElection() countdown.Signal(); }; - leaderElector.RunAsync().Wait(); + leaderElector.RunUntilLeadershipLostAsync().Wait(); }); countdown.Wait(TimeSpan.FromSeconds(10)); @@ -164,7 +164,7 @@ public void LeaderElection() lockAStopLeading.Set(); }; - leaderElector.RunAsync().Wait(); + leaderElector.RunUntilLeadershipLostAsync().Wait(); }); @@ -186,7 +186,7 @@ public void LeaderElection() testLeaderElectionLatch.Signal(); }; - leaderElector.RunAsync().Wait(); + leaderElector.RunUntilLeadershipLostAsync().Wait(); }); testLeaderElectionLatch.Wait(TimeSpan.FromSeconds(15)); @@ -272,7 +272,7 @@ public void LeaderElectionWithRenewDeadline() countdown.Signal(); }; - leaderElector.RunAsync().Wait(); + leaderElector.RunUntilLeadershipLostAsync().Wait(); }); countdown.Wait(TimeSpan.FromSeconds(15)); @@ -305,7 +305,7 @@ public void LeaderElectionThrowException() try { - leaderElector.RunAsync().Wait(); + leaderElector.RunUntilLeadershipLostAsync().Wait(); } catch (Exception e) { @@ -362,7 +362,7 @@ public void LeaderElectionReportLeaderOnStart() countdown.Signal(); }; - Task.Run(() => leaderElector.RunAsync()); + Task.Run(() => leaderElector.RunUntilLeadershipLostAsync()); countdown.Wait(TimeSpan.FromSeconds(10)); Assert.True(notifications.SequenceEqual(new[] @@ -403,7 +403,7 @@ public void LeaderElectionShouldReportLeaderItAcquiresOnStart() countdown.Signal(); }; - Task.Run(() => leaderElector.RunAsync()); + Task.Run(() => leaderElector.RunUntilLeadershipLostAsync()); countdown.Wait(TimeSpan.FromSeconds(10)); Assert.True(notifications.SequenceEqual(new[] { "foo1" }));