public static async Task ProcessCustomerAsync( [QueueTrigger(OperationConstants.CustomersQueueName, Connection = "StorageConnectionString")] ProcessCustomerDetail customerDetail, [DataRepository(DataType = typeof(AuditRecord))] DocumentRepository <AuditRecord> auditRecordRepository, [DataRepository(DataType = typeof(CustomerDetail))] DocumentRepository <CustomerDetail> customerRepository, [DataRepository(DataType = typeof(SubscriptionDetail))] DocumentRepository <SubscriptionDetail> subscriptionRepository, [PartnerService( ApplicationId = "{PartnerCenterEndpoint.ApplicationId}", Endpoint = "{PartnerCenterEndpoint.ServiceAddress}", SecretName = "{PartnerCenterEndpoint.ApplicationSecretId}", ApplicationTenantId = "{PartnerCenterEndpoint.TenantId}", Resource = "https://graph.windows.net")] IPartner partner, [Queue(OperationConstants.SecurityQueueName, Connection = "StorageConnectionString")] ICollector <SecurityDetail> securityQueue, [Queue(OperationConstants.UtilizationQueueName, Connection = "StorageConnectionString")] ICollector <ProcessSubscriptionDetail> utilizationQueue, ILogger log) { IEnumerable <AuditRecord> auditRecords; List <SubscriptionDetail> subscriptions; int period; try { log.LogInformation($"Attempting to process information for {customerDetail.Customer.Id}."); //pull in customer details from PartnerCenter try { Customer customer = await partner.Customers[customerDetail.Customer.Id].GetAsync().ConfigureAwait(false); customerDetail.Customer.BillingProfile = customer.BillingProfile; if (customerDetail.Customer.RemovedFromPartnerCenter == true) { customerDetail.Customer.LastProcessed = null; } customerDetail.Customer.RemovedFromPartnerCenter = false; } catch (ServiceClientException ex) { customerDetail.Customer.ProcessException = ex; } if (customerDetail.Customer.RemovedFromPartnerCenter) { // The customer no longer has relationship with the partner. So, it should not be processed. return; } // Configure the value indicating the number of days of score results to retrieve starting from current date. period = (customerDetail.Customer.LastProcessed == null) ? 30 : (DateTimeOffset.UtcNow - customerDetail.Customer.LastProcessed).Value.Days; // Ensure that the period is at least 1 or greater. This ensure the request to retrieve data is succesfully. if (period < 1) { period = 1; } if (period >= 30) { period = 30; try { customerDetail.Customer.ProcessException = null; subscriptions = await GetSubscriptionsAsync( partner, customerDetail.Customer.Id).ConfigureAwait(false); } catch (ServiceClientException ex) { customerDetail.Customer.ProcessException = ex; subscriptions = null; log.LogWarning($"Encountered an exception when processing {customerDetail.Customer.Id}. Check the customer record for more information."); } } else { // Obtain a list of audit records for the specified customer that happened since the customer was last processed. auditRecords = await auditRecordRepository.GetAsync( r => r.CustomerId == customerDetail.Customer.Id && r.OperationDate >= customerDetail.Customer.LastProcessed, customerDetail.Customer.EnvironmentId).ConfigureAwait(false); subscriptions = await subscriptionRepository .GetAsync(s => s.TenantId == customerDetail.Customer.Id, customerDetail.Customer.Id) .ConfigureAwait(false); // Since the period is less than 30 we can utilize the audit logs to reconstruct any subscriptions that were created. subscriptions = await AuditRecordConverter.ConvertAsync( partner, auditRecords, subscriptions, customerDetail.Customer).ConfigureAwait(false); } if (subscriptions?.Count > 0) { await subscriptionRepository.AddOrUpdateAsync( subscriptions, customerDetail.Customer.Id).ConfigureAwait(false); } if (customerDetail.Customer.ProcessException == null) { securityQueue.Add(new SecurityDetail { AppEndpoint = customerDetail.AppEndpoint, Customer = customerDetail.Customer, Period = period.ToString(CultureInfo.InvariantCulture) }); if (customerDetail.ProcessAzureUsage) { foreach (SubscriptionDetail subscription in subscriptions.Where(s => s.BillingType == BillingType.Usage)) { utilizationQueue.Add(new ProcessSubscriptionDetail { PartnerCenterEndpoint = customerDetail.PartnerCenterEndpoint, Subscription = subscription }); } } customerDetail.Customer.LastProcessed = DateTimeOffset.UtcNow; } await customerRepository.AddOrUpdateAsync(customerDetail.Customer).ConfigureAwait(false); log.LogInformation($"Successfully processed customer {customerDetail.Customer.Id}. Exception(s): {(customerDetail.Customer.ProcessException != null ? "yes" : "no")}"); } finally { auditRecords = null; subscriptions = null; } }
public static async Task ProcessPartnerAsync( [QueueTrigger(OperationConstants.PartnersQueueName, Connection = "StorageConnectionString")] EnvironmentDetail environment, [DataRepository(DataType = typeof(AuditRecord))] DocumentRepository <AuditRecord> auditRecordRepository, [DataRepository(DataType = typeof(CustomerDetail))] DocumentRepository <CustomerDetail> customerRepository, [DataRepository( DataType = typeof(EnvironmentDetail))] DocumentRepository <EnvironmentDetail> environmentRepository, [PartnerService( ApplicationId = "{PartnerCenterEndpoint.ApplicationId}", Endpoint = "{PartnerCenterEndpoint.ServiceAddress}", SecretName = "{PartnerCenterEndpoint.ApplicationSecretId}", ApplicationTenantId = "{PartnerCenterEndpoint.TenantId}", Resource = "https://graph.windows.net")] IPartner client, [Queue(OperationConstants.CustomersQueueName, Connection = "StorageConnectionString")] ICollector <ProcessCustomerDetail> customerQueue, ILogger log) { List <AuditRecord> auditRecords; List <CustomerDetail> customers; int days; try { log.LogInformation($"Starting to process the {environment.FriendlyName} CSP environment."); // Calculate the number of days that have gone by, since the last successful synchronization. days = (environment.LastProcessed == null) ? 30 : (DateTimeOffset.UtcNow - environment.LastProcessed).Days; if (days >= 90) { // Only audit records for the past 90 days are available from Partner Center. days = 89; } else if (days <= 0) { // Ensure that in all circumstances at least one day of records will be returned. days = 1; } if (days >= 30) { customers = await GetCustomersAsync(client, environment).ConfigureAwait(false); } else { auditRecords = await GetAuditRecordsAsyc( client, DateTime.UtcNow.AddDays(-days), DateTime.UtcNow).ConfigureAwait(false); if (auditRecords.Count > 0) { log.LogInformation($"Importing {auditRecords.Count} audit records available between now and the previous day for the {environment.FriendlyName} Region."); // Add, or update, each audit record to the database. await auditRecordRepository.AddOrUpdateAsync( auditRecords, environment.Id).ConfigureAwait(false); } customers = await customerRepository.GetAsync(c => c.EnvironmentId == environment.Id).ConfigureAwait(false); log.LogInformation($"Retrieved {customers.Count()} customers from the repository for the {environment.FriendlyName} Region"); customers = await AuditRecordConverter.ConvertAsync( client, auditRecords, customers, new Dictionary <string, string> { { "EnvironmentId", environment.Id } }, log).ConfigureAwait(false); } log.LogInformation($"Saving {customers.Count()} customers to the repository for the {environment.FriendlyName} Region"); // Add, or update, each customer to the database. await customerRepository.AddOrUpdateAsync(customers).ConfigureAwait(false); log.LogInformation($"Adding {customers.Count()} customers to the queue for processing for the {environment.FriendlyName} Region"); foreach (CustomerDetail customer in customers) { // Write the customer to the customers queue to start processing the customer. customerQueue.Add(new ProcessCustomerDetail { AppEndpoint = environment.AppEndpoint, Customer = customer, PartnerCenterEndpoint = environment.PartnerCenterEndpoint, ProcessAzureUsage = environment.ProcessAzureUsage }); } environment.LastProcessed = DateTimeOffset.UtcNow; await environmentRepository.AddOrUpdateAsync(environment).ConfigureAwait(false); log.LogInformation($"Successfully processed the {environment.FriendlyName} CSP environment."); } finally { auditRecords = null; customers = null; } }