예제 #1
0
        public async Task OnMessageDispatchedAsync(OutputResult outputResult)
        {
            // If dispatch failed, update the history table with target -1
            if (!outputResult.Delivered)
            {
                var historyTable = await GetHistoryTableAsync(outputResult.EngagementAccount);

                var historyEntity = new MessageHistoryTableEntity(outputResult.EngagementAccount, outputResult.MessageId.ToString());
                if (historyEntity == null)
                {
                    EmailProviderEventSource.Current.Warning(EmailProviderEventSource.EmptyTrackingId, this, nameof(this.OnMessageDispatchedAsync), OperationStates.Dropped, $"Does not find record for messageId={outputResult.MessageId}");
                    return;
                }

                historyEntity.Targets = -1;
                await MessageHistoryTableEntity.InsertOrMergeAsync(historyTable, historyEntity);
            }

            // If succeed, update the in-progress table
            else
            {
                // Insert in-progress table
                var inProgressEntity = new ReportInProgressTableEntity(outputResult.EngagementAccount, outputResult.MessageId, outputResult.DeliveryResponse.CustomMessageId);
                await ReportInProgressTableEntity.InsertOrMergeAsync(reportInProgressTable, inProgressEntity);
            }
        }
예제 #2
0
        public MessageAuditTableEntity(MessageHistoryTableEntity history)
        {
            this.EngagementAccount = history.EngagementAccount;
            this.MessageId         = history.MessageId;
            this.MessageBody       = history.MessageBody;
            this.SendTime          = history.SendTime;
            this.LastUpdateTime    = history.LastUpdateTime;

            this.PartitionKey = this.EngagementAccount;
            this.RowKey       = this.MessageId;
        }
예제 #3
0
        public async Task OnMessageSentAsync(InputMessage message, EmailMessageInfoExtension extension)
        {
            // Create record in history table
            var historyTable = await GetHistoryTableAsync(message.MessageInfo.EngagementAccount);

            if (historyTable == null)
            {
                // Create the table in case any issue in account initialize
                historyTable = await GetHistoryTableAsync(message.MessageInfo.EngagementAccount, true);
            }

            var history = new MessageHistoryTableEntity(message, extension);
            await MessageHistoryTableEntity.InsertOrMergeAsync(historyTable, history);

            // Create record in audit table
            var audit = new MessageAuditTableEntity(history);
            await MessageAuditTableEntity.InsertOrMergeAsync(auditTable, audit);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
            }
        }
 public static async Task InsertOrMergeAsync(CloudTable table, MessageHistoryTableEntity entity)
 {
     var operation = TableOperation.InsertOrMerge(entity);
     await table.ExecuteAsync(operation);
 }