public async Task ExecuteAsync() { var stopwatch = Stopwatch.StartNew(); var outcome = JobOutcome.Failure; try { _logger.LogInformation("Fetching old owner data from blob storage."); var storageResult = await _ownerDataClient.ReadLatestIndexedAsync(); _logger.LogInformation("Fetching new owner data from the database."); var databaseResult = await _databaseFetcher.GetPackageIdToOwnersAsync(); _logger.LogInformation("Detecting owner changes."); var changes = _ownerSetComparer.Compare(storageResult.Result, databaseResult); var changesBag = new ConcurrentBag <IdAndValue <string[]> >(changes.Select(x => new IdAndValue <string[]>(x.Key, x.Value))); _logger.LogInformation("{Count} package IDs have owner changes.", changesBag.Count); if (!changes.Any()) { outcome = JobOutcome.NoOp; return; } _logger.LogInformation( "Starting {Count} workers pushing owners changes to Azure Search.", _options.Value.MaxConcurrentBatches); await ParallelAsync.Repeat(() => WorkAsync(changesBag), _options.Value.MaxConcurrentBatches); _logger.LogInformation("All of the owner changes have been pushed to Azure Search."); // Persist in storage the list of all package IDs that have owner changes. This allows debugging and future // analytics on frequency of ownership changes. _logger.LogInformation("Uploading the package IDs that have owner changes to blob storage."); await _ownerDataClient.UploadChangeHistoryAsync(changes.Keys.ToList()); _logger.LogInformation("Uploading the new owner data to blob storage."); await _ownerDataClient.ReplaceLatestIndexedAsync(databaseResult, storageResult.AccessCondition); outcome = JobOutcome.Success; } finally { stopwatch.Stop(); _telemetryService.TrackUpdateOwnersCompleted(outcome, stopwatch.Elapsed); } }