public async Task <MessageRecord> GetMessageReportAsync(string engagementAccount, string messageId) { // Get from history table for metadata var historyTable = await GetHistoryTableAsync(engagementAccount); var historyEntity = await MessageHistoryTableEntity.GetAsync(historyTable, engagementAccount, messageId); if (historyEntity == null) { return(null); } var record = new MessageRecord { MessageId = historyEntity.MessageId, SendTime = historyEntity.SendTime, Targets = historyEntity.Targets, Delivered = historyEntity.Delivered, Opened = historyEntity.Opened, Clicked = historyEntity.Clicked, CustomMessageId = historyEntity.CustomMessageId }; // Try to get from in-progress table var inProgressEntity = await ReportInProgressTableEntity.GetAsync(reportInProgressTable, engagementAccount, messageId); if (inProgressEntity != null) { record.Targets = inProgressEntity.Targets; record.Delivered = inProgressEntity.Delivered; record.Opened = inProgressEntity.Opened; record.Clicked = inProgressEntity.Clicked; record.CustomMessageId = inProgressEntity.CustomMessageId; } return(record); }
public async Task <bool> OnReportUpdatedAsync(string engagementAccount, Report report) { try { // Get record in in-progress table var inProgressEntity = await ReportInProgressTableEntity.GetAsync(reportInProgressTable, engagementAccount, report.MessageIdentifer.MessageId); if (inProgressEntity == null) { // Record should be already in history table var historyTable = await GetHistoryTableAsync(engagementAccount); var historyEntity = await MessageHistoryTableEntity.GetAsync(historyTable, engagementAccount, report.MessageIdentifer.MessageId); if (historyEntity == null) { EmailProviderEventSource.Current.Warning(EmailProviderEventSource.EmptyTrackingId, this, nameof(this.OnReportUpdatedAsync), OperationStates.Dropped, $"Does not find record for messageId={report.MessageIdentifer.MessageId}"); return(false); } // TODO: if after 24h we get new number of target shall we charge? historyEntity.Targets = report.TotalTarget; historyEntity.Delivered = report.TotalDelivered; historyEntity.Opened = report.TotalOpened; historyEntity.Clicked = report.TotalClicked; historyEntity.LastUpdateTime = DateTime.UtcNow; await MessageHistoryTableEntity.InsertOrMergeAsync(historyTable, historyEntity); return(true); } var lastTarget = inProgressEntity.Targets; // Update the record in in-progress table inProgressEntity.Targets = report.TotalTarget; inProgressEntity.Delivered = report.TotalDelivered; inProgressEntity.Opened = report.TotalOpened; inProgressEntity.Clicked = report.TotalClicked; inProgressEntity.LastUpdateTime = DateTime.UtcNow; var updated = await ReportInProgressTableEntity.TryUpdateAsync(reportInProgressTable, inProgressEntity); // New target sent, do the charge (only if update succeed) if (updated && lastTarget < report.TotalTarget) { try { var delta = report.TotalTarget - lastTarget; // Get account detail var account = await this.store.GetAccountAsync(engagementAccount); metricManager.LogDeliverSuccess(delta, engagementAccount, account?.SubscriptionId ?? string.Empty); var usage = new ResourceUsageRecord(); usage.EngagementAccount = engagementAccount; usage.UsageType = ResourceUsageType.EmailMessage; usage.Quantity = delta; await this.billingAgent.StoreBillingUsageAsync(new List <ResourceUsageRecord> { usage }, CancellationToken.None); EmailProviderEventSource.Current.Info(EmailProviderEventSource.EmptyTrackingId, this, nameof(this.OnReportUpdatedAsync), OperationStates.Succeeded, $"Usage pushed to billing service account={engagementAccount} quantity={usage.Quantity}"); } catch (Exception ex) { // We should monitor for billing failure EmailProviderEventSource.Current.CriticalException(EmailProviderEventSource.EmptyTrackingId, this, nameof(this.OnReportUpdatedAsync), OperationStates.Failed, $"Failed at pushing to billing service account={engagementAccount}", ex); } } // If the record in in-progress for 24h, treat it as completed and move it to history table if (inProgressEntity.Timestamp.AddHours(Constants.ReportInProgressIntervalByHours) < DateTime.UtcNow) { // Record should be already in history table var historyTable = await GetHistoryTableAsync(engagementAccount); var historyEntity = new MessageHistoryTableEntity(inProgressEntity); await MessageHistoryTableEntity.InsertOrMergeAsync(historyTable, historyEntity); await ReportInProgressTableEntity.DeleteAsync(reportInProgressTable, inProgressEntity); } return(true); } catch (Exception ex) { EmailProviderEventSource.Current.ErrorException(EmailProviderEventSource.EmptyTrackingId, this, nameof(this.OnReportUpdatedAsync), OperationStates.Failed, string.Empty, ex); return(false); } }