public async Task PersistHandledMessage(InboxRecord inboxMessage) { const string sql = @"MERGE INTO [{0}].[{1}InboxRecord] WITH (updlock, rowlock) AS tgt USING (SELECT @ContentId, @CheckMessageOrderType) AS src (ContentId, CheckMessageOrderType) ON tgt.ContentId = src.ContentId and tgt.CheckMessageOrderType = src.CheckMessageOrderType WHEN MATCHED THEN UPDATE SET ContentVersion = @ContentVersion, ContentId = @ContentId, ModifiedAtUtc = @ModifiedAtUtc, MessageId = @MessageId WHEN NOT MATCHED THEN INSERT (ContentId, ContentVersion, CheckMessageOrderType, ModifiedAtUtc, MessageId) VALUES (@ContentId, @ContentVersion, @CheckMessageOrderType, @ModifiedAtUtc, @MessageId);"; object[] parameters = { dbSchemaName, dbTablePrefix }; await this.Database.ExecuteSqlCommandAsync( string.Format(sql, parameters), new SqlParameter("@ContentId", inboxMessage.ContentId), new SqlParameter("@ContentVersion", inboxMessage.ContentVersion), new SqlParameter("@CheckMessageOrderType", inboxMessage.CheckMessageOrderType), new SqlParameter("@ModifiedAtUtc", inboxMessage.ModifiedAtUtc), new SqlParameter("@MessageId", inboxMessage.MessageId)) .ConfigureAwait(false); }
public async Task PersistDiscardedMessage(InboxRecord inboxMessage, long latestHandledVersion) { //Add or update const string sql = @"INSERT INTO [{0}].[{1}InboxRecordDiscarded] (ContentId, ContentVersion, LatestContentVersion, CheckMessageOrderType, ModifiedAtUtc, MessageId) VALUES (@ContentId, @ContentVersion, @LatestContentVersion, @CheckMessageOrderType, @ModifiedAtUtc, @MessageId)" ; object[] parameters = { dbSchemaName, dbTablePrefix }; await this.Database.ExecuteSqlCommandAsync( string.Format(sql, parameters), new SqlParameter("@ContentId", inboxMessage.ContentId), new SqlParameter("@ContentVersion", inboxMessage.ContentVersion), new SqlParameter("@LatestContentVersion", latestHandledVersion), new SqlParameter("@CheckMessageOrderType", inboxMessage.CheckMessageOrderType), new SqlParameter("@ModifiedAtUtc", inboxMessage.ModifiedAtUtc), new SqlParameter("@MessageId", inboxMessage.MessageId)) .ConfigureAwait(false); }
public override async Task Invoke(IInvokeHandlerContext context, Func <Task> next) { var session = context.SynchronizedStorageSession; var sqlPersistenceSession = session.SqlPersistenceSession(); var dbContext = (InboxDbContext)Activator.CreateInstance(typeof(InboxDbContext), sqlPersistenceSession.Connection); using (dbContext) { dbContext.Database.UseTransaction(sqlPersistenceSession.Transaction); context.MessageHeaders.TryGetValue("ContentId", out string contentId); long contentVersion = GetContentVersionFrom(context.MessageHeaders); var checkMessageOrderType = GetCheckMessageOrderType(context); var latestHandledVersion = await dbContext.GetLatestMessageVersion(contentId, checkMessageOrderType).ConfigureAwait(false); var shouldBeHandled = latestHandledVersion == null || contentVersion > latestHandledVersion; var inboxMessage = new InboxRecord { ContentId = contentId, ContentVersion = contentVersion, CheckMessageOrderType = checkMessageOrderType, MessageId = Guid.Parse(context.MessageId), ModifiedAtUtc = DateTime.UtcNow }; if (shouldBeHandled) { log.Info($"Handling message: Type: {checkMessageOrderType}, ContentId: {contentId}, ContentVersion: {contentVersion}"); await dbContext.PersistHandledMessage(inboxMessage).ConfigureAwait(false); await next().ConfigureAwait(false); } else { string discardedReason = $"Discarding message since a newer version has already been processed: Type: {checkMessageOrderType}, ContentId: {contentId}, ContentVersion: {contentVersion}"; log.Info(discardedReason); await dbContext.PersistDiscardedMessage(inboxMessage, latestHandledVersion.GetValueOrDefault()).ConfigureAwait(false); context.Headers.Add("InboxDiscardedReason", discardedReason); } } }