コード例 #1
0
        public async Task <bool> UpdateAsync(LeaderElectionRecord record, CancellationToken cancellationToken = default)
        {
            var metaObj = Interlocked.CompareExchange(ref metaObjCache, null, null);

            if (metaObj == null)
            {
                throw new InvalidOperationException("endpoint not initialized, call get or create first");
            }

            metaObj = SetLeaderElectionRecord(record, metaObj);

            try
            {
                var replacedObj = await ReplaceMetaObjectAsync(client, metaObj, name, ns, cancellationToken).ConfigureAwait(false);

                Interlocked.Exchange(ref metaObjCache, replacedObj);
                return(true);
            }
            catch (HttpOperationException)
            {
                // ignore
            }

            return(false);
        }
コード例 #2
0
        public async Task <bool> CreateAsync(LeaderElectionRecord record, CancellationToken cancellationToken = default)
        {
            var metaObj = new T
            {
                Metadata = new V1ObjectMeta()
                {
                    Name = name, NamespaceProperty = ns
                },
            };

            metaObj = SetLeaderElectionRecord(record, metaObj);

            try
            {
                var createdObj = await CreateMetaObjectAsync(client, metaObj, ns, cancellationToken)
                                 .ConfigureAwait(false);

                Interlocked.Exchange(ref metaObjCache, createdObj);
                return(true);
            }
            catch (HttpOperationException)
            {
                // ignore
            }

            return(false);
        }
コード例 #3
0
        protected override T SetLeaderElectionRecord(LeaderElectionRecord record, T metaObj)
        {
            metaObj.SetAnnotation(
                LeaderElectionRecordAnnotationKey,
                JsonConvert.SerializeObject(record, serializationSettings));

            return(metaObj);
        }
コード例 #4
0
        private async Task UpdateLeaderRecord(LeaderElectionRecord record, CancellationToken token)
        {
            this.logger.LogInformation("Updating leader record {leaderObjectName}", this.leaderObjectName);

            var annotations = new Dictionary <string, string>()
            {
                [LeaderAnnotationName] = JsonSerializer.Serialize(record),
            };

            await this.client.PutEndpointAnnotationsAsync(this.ns, this.leaderObjectName, annotations, token);
        }
コード例 #5
0
            public Task <bool> CreateAsync(
                LeaderElectionRecord record,
                CancellationToken cancellationToken = default)
            {
                lock (Lockobj)
                {
                    if (leaderRecord != null)
                    {
                        return(Task.FromResult(false));
                    }

                    leaderRecord = record;
                    OnCreate?.Invoke(record);
                    return(Task.FromResult(true));
                }
            }
コード例 #6
0
            public Task <bool> UpdateAsync(LeaderElectionRecord record, CancellationToken cancellationToken = default)
            {
                lock (Lockobj)
                {
                    OnTryUpdate?.Invoke(record);

                    if (UpdateWillFail?.Invoke() == true)
                    {
                        return(Task.FromResult(false));
                    }

                    var oldRecord = leaderRecord;
                    leaderRecord = record;
                    OnUpdate?.Invoke(record);
                    if (oldRecord?.HolderIdentity != record.HolderIdentity)
                    {
                        OnChange?.Invoke(record);
                    }

                    return(Task.FromResult(true));
                }
            }
コード例 #7
0
ファイル: LeaseLock.cs プロジェクト: kubernetes-client/csharp
        protected override V1Lease SetLeaderElectionRecord(LeaderElectionRecord record, V1Lease metaObj)
        {
            if (record == null)
            {
                throw new NullReferenceException(nameof(record));
            }

            if (metaObj == null)
            {
                throw new NullReferenceException(nameof(metaObj));
            }

            metaObj.Spec = new V1LeaseSpec()
            {
                AcquireTime          = record.AcquireTime,
                HolderIdentity       = record.HolderIdentity,
                LeaseTransitions     = record.LeaderTransitions,
                LeaseDurationSeconds = record.LeaseDurationSeconds,
                RenewTime            = record.RenewTime,
            };

            return(metaObj);
        }
コード例 #8
0
 public static void ResetGloablRecord()
 {
     leaderRecord = null;
 }
コード例 #9
0
 protected abstract T SetLeaderElectionRecord(LeaderElectionRecord record, T metaObj);
コード例 #10
0
        public async Task BackgroundTaskLoop(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                try
                {
                    var record = await this.EnsureEndpointExists(token);

                    this.IsLeader = record.HolderIdentity == this.identity;
                    this.logger.LogInformation("LeaderElection/BackgroundTaskLoop: IsLeader={isLeader}", this.IsLeader);

                    var now        = DateTimeOffset.UtcNow;
                    var expireDate = new DateTimeOffset((DateTime)(record.RenewTime !)) + TimeSpan.FromSeconds(record.LeaseDurationSeconds);
                    var timeToLive = expireDate - now;

                    if (this.IsLeader)
                    {
                        if (timeToLive > TimeToRefreshBeforeExpiry)
                        {
                            await Task.Delay(timeToLive - TimeToRefreshBeforeExpiry, token);
                        }

                        var newRecord = new LeaderElectionRecord()
                        {
                            HolderIdentity       = this.identity,
                            LeaseDurationSeconds = (int)this.leaseDuration.TotalSeconds,
                            AcquireTime          = record.AcquireTime,
                            RenewTime            = DateTime.UtcNow,
                            LeaderTransitions    = record.LeaderTransitions,
                        };

                        await this.UpdateLeaderRecord(newRecord, token);
                    }
                    else
                    {
                        if (timeToLive < TimeSpan.Zero)
                        {
                            var newRecord = new LeaderElectionRecord()
                            {
                                HolderIdentity       = this.identity,
                                LeaseDurationSeconds = (int)this.leaseDuration.TotalSeconds,
                                AcquireTime          = DateTime.UtcNow,
                                RenewTime            = DateTime.UtcNow,
                                LeaderTransitions    = record.LeaderTransitions + 1,
                            };

                            // it is expired--claim leadership and restart loop
                            await this.UpdateLeaderRecord(newRecord, token);

                            await Task.Delay(TimeToWaitAfterSettingLeader, token);

                            continue;
                        }
                        else
                        {
                            // Give the leader a little extra time to renew
                            await Task.Delay(timeToLive + TimeToWaitAfterSettingLeader, token);
                        }
                    }
                }
                catch (TaskCanceledException e)
                {
                    this.logger.LogError(e, "BackgroundTaskLoop cancelled: {exception}", e.ToString());
                }
            }
        }
コード例 #11
0
 protected bool Equals(LeaderElectionRecord other)
 {
     return(this.HolderIdentity == other?.HolderIdentity &&
            Nullable.Equals(this.AcquireTime, other?.AcquireTime) &&
            Nullable.Equals(this.RenewTime, other?.RenewTime));
 }
コード例 #12
0
        private async Task <bool> TryAcquireOrRenew(CancellationToken cancellationToken)
        {
            var l = config.Lock;
            var leaderElectionRecord = new LeaderElectionRecord()
            {
                HolderIdentity       = l.Identity,
                LeaseDurationSeconds = ( int )config.LeaseDuration.TotalSeconds,
                AcquireTime          = DateTime.UtcNow,
                RenewTime            = DateTime.UtcNow,
                LeaderTransitions    = 0,
            };

            // 1. obtain or create the ElectionRecord

            LeaderElectionRecord oldLeaderElectionRecord = null;

            try
            {
                oldLeaderElectionRecord = await l.GetAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (HttpOperationException e)
            {
                Logger.LogWarning(e, $"ERR {e.Response.StatusCode}");
                if (e.Response.StatusCode != HttpStatusCode.NotFound)
                {
                    return(false);
                }
            }

            if (oldLeaderElectionRecord?.AcquireTime == null ||
                oldLeaderElectionRecord?.RenewTime == null ||
                oldLeaderElectionRecord?.HolderIdentity == null)
            {
                var created = await l.CreateAsync(leaderElectionRecord, cancellationToken).ConfigureAwait(false);

                if (created)
                {
                    observedRecord = leaderElectionRecord;
                    observedTime   = DateTimeOffset.Now;
                    return(true);
                }

                return(false);
            }

            // 2. Record obtained, check the Identity & Time
            if (!Equals(observedRecord, oldLeaderElectionRecord))
            {
                observedRecord = oldLeaderElectionRecord;
                observedTime   = DateTimeOffset.Now;
            }

            if (!string.IsNullOrEmpty(oldLeaderElectionRecord.HolderIdentity) &&
                observedTime + config.LeaseDuration > DateTimeOffset.Now &&
                !IsLeader())
            {
                // lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity
                return(false);
            }

            // 3. We're going to try to update. The leaderElectionRecord is set to it's default
            // here. Let's correct it before updating.
            if (IsLeader())
            {
                leaderElectionRecord.AcquireTime       = oldLeaderElectionRecord.AcquireTime;
                leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions;
            }
            else
            {
                leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions + 1;
            }

            var updated = await l.UpdateAsync(leaderElectionRecord, cancellationToken).ConfigureAwait(false);

            if (!updated)
            {
                return(false);
            }

            observedRecord = leaderElectionRecord;
            observedTime   = DateTimeOffset.Now;

            return(true);
        }
コード例 #13
0
 public async Task <bool> UpdateAsync(LeaderElectionRecord record, CancellationToken cancellationToken = default)
 {
     return(await primary.UpdateAsync(record, cancellationToken).ConfigureAwait(false) &&
            await secondary.UpdateAsync(record, cancellationToken).ConfigureAwait(false));
 }
コード例 #14
0
 protected override T SetLeaderElectionRecord(LeaderElectionRecord record, T metaObj)
 {
     metaObj.SetAnnotation(LeaderElectionRecordAnnotationKey, KubernetesJson.Serialize(record));
     return(metaObj);
 }