Beispiel #1
0
        async Task RunLoopAsync(CancellationToken cancellationToken) // throws Exception, ExceptionWithAction
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                ILeaseManager leaseManager           = this.host.LeaseManager;
                Dictionary <string, Lease> allLeases = new Dictionary <string, Lease>();

                // Inspect all leases.
                // Acquire any expired leases.
                // Renew any leases that currently belong to us.
                IEnumerable <Task <Lease> > gettingAllLeases = leaseManager.GetAllLeases();
                List <Lease> leasesOwnedByOthers             = new List <Lease>();
                int          ourLeaseCount = 0;
                foreach (Task <Lease> getLeaseTask in gettingAllLeases)
                {
                    try
                    {
                        Lease possibleLease = await getLeaseTask.ConfigureAwait(false);

                        allLeases[possibleLease.PartitionId] = possibleLease;
                        if (await possibleLease.IsExpired().ConfigureAwait(false))
                        {
                            ProcessorEventSource.Log.PartitionPumpInfo(this.host.Id, possibleLease.PartitionId, "Trying to acquire lease.");
                            if (await leaseManager.AcquireLeaseAsync(possibleLease).ConfigureAwait(false))
                            {
                                ourLeaseCount++;
                            }
                            else
                            {
                                // Probably failed because another host stole it between get and acquire
                                leasesOwnedByOthers.Add(possibleLease);
                            }
                        }
                        else if (possibleLease.Owner == this.host.HostName)
                        {
                            ProcessorEventSource.Log.PartitionPumpInfo(this.host.Id, possibleLease.PartitionId, "Trying to renew lease.");

                            // Try to renew the lease. If successful then this lease belongs to us,
                            // if throws LeaseLostException then we don't own it anymore.
                            try
                            {
                                await leaseManager.RenewLeaseAsync(possibleLease).ConfigureAwait(false);

                                ourLeaseCount++;
                            }
                            catch (LeaseLostException)
                            {
                                // Probably failed because another host stole it between get and renew
                                leasesOwnedByOthers.Add(possibleLease);
                            }
                        }
                        else
                        {
                            leasesOwnedByOthers.Add(possibleLease);
                        }
                    }
                    catch (Exception e)
                    {
                        ProcessorEventSource.Log.EventProcessorHostWarning(this.host.Id, "Failure during getting/acquiring/renewing lease, skipping", e.ToString());
                        this.host.EventProcessorOptions.NotifyOfException(this.host.HostName, "N/A", e, EventProcessorHostActionStrings.CheckingLeases);
                    }
                }

                // Grab more leases if available and needed for load balancing
                if (leasesOwnedByOthers.Count > 0)
                {
                    Lease stealThisLease = WhichLeaseToSteal(leasesOwnedByOthers, ourLeaseCount);
                    if (stealThisLease != null)
                    {
                        try
                        {
                            ProcessorEventSource.Log.PartitionPumpStealLeaseStart(this.host.Id, stealThisLease.PartitionId);
                            if (await leaseManager.AcquireLeaseAsync(stealThisLease).ConfigureAwait(false))
                            {
                                // Succeeded in stealing lease
                                ProcessorEventSource.Log.PartitionPumpStealLeaseStop(this.host.Id, stealThisLease.PartitionId);
                            }
                            else
                            {
                                ProcessorEventSource.Log.EventProcessorHostWarning(this.host.Id,
                                                                                   "Failed to steal lease for partition " + stealThisLease.PartitionId, null);
                            }
                        }
                        catch (Exception e)
                        {
                            ProcessorEventSource.Log.EventProcessorHostError(this.host.Id,
                                                                             "Exception during stealing lease for partition " + stealThisLease.PartitionId, e.ToString());
                            this.host.EventProcessorOptions.NotifyOfException(this.host.HostName,
                                                                              stealThisLease.PartitionId, e, EventProcessorHostActionStrings.StealingLease);
                        }
                    }
                }

                // Update pump with new state of leases.
                foreach (string partitionId in allLeases.Keys)
                {
                    try
                    {
                        Lease updatedLease = allLeases[partitionId];
                        ProcessorEventSource.Log.EventProcessorHostInfo(this.host.Id, $"Lease on partition {updatedLease.PartitionId} owned by {updatedLease.Owner}");
                        if (updatedLease.Owner == this.host.HostName)
                        {
                            await this.CheckAndAddPumpAsync(partitionId, updatedLease).ConfigureAwait(false);
                        }
                        else
                        {
                            await this.RemovePumpAsync(partitionId, CloseReason.LeaseLost).ConfigureAwait(false);
                        }
                    }
                    catch (Exception e)
                    {
                        ProcessorEventSource.Log.EventProcessorHostError(this.host.Id, $"Exception during add/remove pump on partition {partitionId}", e.Message);
                        this.host.EventProcessorOptions.NotifyOfException(this.host.HostName, partitionId, e, EventProcessorHostActionStrings.PartitionPumpManagement);
                    }
                }

                try
                {
                    await Task.Delay(leaseManager.LeaseRenewInterval, cancellationToken).ConfigureAwait(false);
                }
                catch (TaskCanceledException)
                {
                    // Bail on the async work if we are canceled.
                }
            }
        }
Beispiel #2
0
        async Task RunLoopAsync(CancellationToken cancellationToken) // throws Exception, ExceptionWithAction
        {
            var loopStopwatch = new Stopwatch();

            while (!cancellationToken.IsCancellationRequested)
            {
                // Mark start time so we can use the duration taken to calculate renew interval.
                loopStopwatch.Restart();

                ILeaseManager leaseManager           = this.host.LeaseManager;
                Dictionary <string, Lease> allLeases = new Dictionary <string, Lease>();

                // Inspect all leases.
                // Acquire any expired leases.
                // Renew any leases that currently belong to us.
                IEnumerable <Task <Lease> > gettingAllLeases = leaseManager.GetAllLeases();
                List <Lease> leasesOwnedByOthers             = new List <Lease>();
                var          renewLeaseTasks = new List <Task>();
                int          ourLeaseCount   = 0;

                // First thing is first, renew owned leases.
                foreach (Task <Lease> getLeaseTask in gettingAllLeases)
                {
                    try
                    {
                        var lease = await getLeaseTask.ConfigureAwait(false);

                        allLeases[lease.PartitionId] = lease;
                        if (lease.Owner == this.host.HostName)
                        {
                            ourLeaseCount++;
                            ProcessorEventSource.Log.PartitionPumpInfo(this.host.HostName, lease.PartitionId, "Trying to renew lease.");
                            renewLeaseTasks.Add(leaseManager.RenewLeaseAsync(lease).ContinueWith(renewResult =>
                            {
                                if (renewResult.IsFaulted || !renewResult.Result)
                                {
                                    // Might have failed due to intermittent error or lease-lost.
                                    // Just log here, expired leases will be picked by same or another host anyway.
                                    ProcessorEventSource.Log.PartitionPumpError(this.host.HostName, lease.PartitionId, "Failed to renew lease.", renewResult.Exception?.Message);
                                    this.host.EventProcessorOptions.NotifyOfException(this.host.HostName, lease.PartitionId, renewResult.Exception, EventProcessorHostActionStrings.RenewingLease);
                                }
                            }));
                        }
                        else
                        {
                            leasesOwnedByOthers.Add(lease);
                        }
                    }
                    catch (Exception e)
                    {
                        ProcessorEventSource.Log.EventProcessorHostError(this.host.HostName, "Failure during checking lease.", e.ToString());
                        this.host.EventProcessorOptions.NotifyOfException(this.host.HostName, "N/A", e, EventProcessorHostActionStrings.CheckingLeases);
                    }
                }

                // Wait until we are done with renewing our own leases here.
                // In theory, this should never throw, error are logged and notified in the renew tasks.
                await Task.WhenAll(renewLeaseTasks.ToArray()).ConfigureAwait(false);

                ProcessorEventSource.Log.EventProcessorHostInfo(this.host.HostName, "Lease renewal is finished.");

                // Check any expired leases that we can grab here.
                foreach (var possibleLease in allLeases.Values)
                {
                    try
                    {
                        if (await possibleLease.IsExpired().ConfigureAwait(false))
                        {
                            bool isExpiredLeaseOwned = possibleLease.Owner == this.host.HostName;
                            ProcessorEventSource.Log.PartitionPumpInfo(this.host.HostName, possibleLease.PartitionId, "Trying to acquire lease.");
                            if (await leaseManager.AcquireLeaseAsync(possibleLease).ConfigureAwait(false))
                            {
                                ProcessorEventSource.Log.PartitionPumpInfo(this.host.HostName, possibleLease.PartitionId, "Acquired lease.");

                                // Don't double count if we have already counted this lease at the beginning of the loop.
                                if (!isExpiredLeaseOwned)
                                {
                                    ourLeaseCount++;
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        ProcessorEventSource.Log.PartitionPumpError(this.host.HostName, possibleLease.PartitionId, "Failure during acquiring lease", e.ToString());
                        this.host.EventProcessorOptions.NotifyOfException(this.host.HostName, possibleLease.PartitionId, e, EventProcessorHostActionStrings.CheckingLeases);
                    }
                }

                // Grab more leases if available and needed for load balancing
                if (leasesOwnedByOthers.Count > 0)
                {
                    Lease stealThisLease = WhichLeaseToSteal(leasesOwnedByOthers, ourLeaseCount);
                    if (stealThisLease != null)
                    {
                        try
                        {
                            ProcessorEventSource.Log.PartitionPumpStealLeaseStart(this.host.HostName, stealThisLease.PartitionId);
                            if (await leaseManager.AcquireLeaseAsync(stealThisLease).ConfigureAwait(false))
                            {
                                // Succeeded in stealing lease
                                ProcessorEventSource.Log.PartitionPumpStealLeaseStop(this.host.HostName, stealThisLease.PartitionId);
                            }
                            else
                            {
                                ProcessorEventSource.Log.EventProcessorHostWarning(this.host.HostName,
                                                                                   "Failed to steal lease for partition " + stealThisLease.PartitionId, null);
                            }
                        }
                        catch (Exception e)
                        {
                            ProcessorEventSource.Log.EventProcessorHostError(this.host.HostName,
                                                                             "Exception during stealing lease for partition " + stealThisLease.PartitionId, e.ToString());
                            this.host.EventProcessorOptions.NotifyOfException(this.host.HostName,
                                                                              stealThisLease.PartitionId, e, EventProcessorHostActionStrings.StealingLease);
                        }
                    }
                }

                // Update pump with new state of leases.
                foreach (string partitionId in allLeases.Keys)
                {
                    try
                    {
                        Lease updatedLease = allLeases[partitionId];
                        ProcessorEventSource.Log.EventProcessorHostInfo(this.host.HostName, $"Lease on partition {updatedLease.PartitionId} owned by {updatedLease.Owner}");
                        if (updatedLease.Owner == this.host.HostName)
                        {
                            await this.CheckAndAddPumpAsync(partitionId, updatedLease).ConfigureAwait(false);
                        }
                        else
                        {
                            await this.RemovePumpAsync(partitionId, CloseReason.LeaseLost).ConfigureAwait(false);
                        }
                    }
                    catch (Exception e)
                    {
                        ProcessorEventSource.Log.EventProcessorHostError(this.host.HostName, $"Exception during add/remove pump on partition {partitionId}", e.Message);
                        this.host.EventProcessorOptions.NotifyOfException(this.host.HostName, partitionId, e, EventProcessorHostActionStrings.PartitionPumpManagement);
                    }
                }

                try
                {
                    // Consider reducing the wait time with last lease-walkthrough's time taken.
                    var elapsedTime = loopStopwatch.Elapsed;
                    if (leaseManager.LeaseRenewInterval > elapsedTime)
                    {
                        await Task.Delay(leaseManager.LeaseRenewInterval.Subtract(elapsedTime), cancellationToken).ConfigureAwait(false);
                    }
                }
                catch (TaskCanceledException)
                {
                    // Bail on the async work if we are canceled.
                }
            }
        }