/// <summary> /// Updates a queued message in the database i.e. in response to an acknowledgement failure /// </summary> /// <param name="queuedMessage">The queued message to delete</param> /// <param name="abandoned">The date/time the message was abandoned (if applicable)</param> /// <param name="cancellationToken">(Optional) A cancellation token through which the /// caller can request cancellation of the update operation</param> /// <returns>Returns a task that completes when the update operation completes</returns> protected virtual async Task UpdateQueuedMessage(QueuedMessage queuedMessage, DateTime?abandoned, CancellationToken cancellationToken = default(CancellationToken)) { var connection = ConnectionProvider.GetConnection(); try { var message = queuedMessage.Message; var headers = message.Headers; var commandBuilder = CommandBuilders.NewUpdateQueuedMessageCommandBuilder(); commandBuilder.MessageId = headers.MessageId; commandBuilder.QueueName = QueueName; commandBuilder.Abandoned = abandoned; commandBuilder.Attempts = queuedMessage.Attempts; using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled)) { using (var command = commandBuilder.BuildDbCommand(connection)) { await command.ExecuteNonQueryAsync(cancellationToken); } scope.Complete(); } } finally { ConnectionProvider.ReleaseConnection(connection); } }
/// <inheritdoc /> protected override async Task <IEnumerable <QueuedMessage> > GetPendingMessages(CancellationToken cancellationToken = default(CancellationToken)) { var queuedMessages = new List <QueuedMessage>(); var connection = ConnectionProvider.GetConnection(); try { var commandBuilder = CommandBuilders.NewSelectPendingMessagesCommandBuilder(); commandBuilder.QueueName = QueueName; using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled)) { using (var command = commandBuilder.BuildDbCommand(connection)) { using (var reader = await command.ExecuteReaderAsync(cancellationToken)) { while (await reader.ReadAsync(cancellationToken)) { try { var record = commandBuilder.BuildQueuedMessageRecord(reader); var messageContent = record.Content; var headers = DeserializeHeaders(record.Headers); var message = new Message(headers, messageContent); if (message.IsEncrypted() && MessageEncryptionService != null) { message = await MessageEncryptionService.Decrypt(message); } #pragma warning disable 612 var principal = await ResolvePrincipal(headers, record.SenderPrincipal); #pragma warning restore 612 message = message.WithoutSecurityToken(); var attempts = record.Attempts; var queuedMessage = new QueuedMessage(message, principal, attempts); queuedMessages.Add(queuedMessage); } catch (Exception ex) { DiagnosticService.Emit(new SQLEventBuilder(this, SQLEventType.SQLMessageRecordFormatError) { Detail = "Error reading previously queued message record; skipping", Exception = ex }.Build()); } } } } scope.Complete(); } } finally { ConnectionProvider.ReleaseConnection(connection); } // SQL calls are not async to avoid the need for TransactionAsyncFlowOption // and dependency on .NET 4.5.1 and later return(queuedMessages.AsEnumerable()); }
public RootCommand Build() { var builder = new CommandLineBuilder( new RootCommand( "Simple communication system between local files and a given metabase server") ) .AddOption(ArgumentBuilder.SetServerOption(SessionCredentials)) .AddOption(ArgumentBuilder.SetUserNameOption(SessionCredentials)) .AddOption(ArgumentBuilder.SetPasswordOption(SessionCredentials)) .AddOption(ArgumentBuilder.SetVerbosityOption(LoggingLevelSwitch)); CommandBuilders.ToList().ForEach(b => builder.AddCommand(b.Build())); return((RootCommand)builder.Command); }
/// <summary> /// Selects all dead messages from the SQL database /// </summary> /// <returns>Returns a task that completes when all records have been selected and whose /// result is the enumerable sequence of the selected records</returns> protected virtual async Task <IEnumerable <QueuedMessage> > GetDeadMessages(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = new CancellationToken()) { var queuedMessages = new List <QueuedMessage>(); var connection = ConnectionProvider.GetConnection(); try { var commandBuilder = CommandBuilders.NewSelectDeadMessagesCommandBuilder(); commandBuilder.QueueName = QueueName; commandBuilder.StartDate = startDate; commandBuilder.EndDate = endDate; using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled)) { using (var command = commandBuilder.BuildDbCommand(connection)) { using (var reader = await command.ExecuteReaderAsync(cancellationToken)) { while (await reader.ReadAsync(cancellationToken)) { var record = commandBuilder.BuildQueuedMessageRecord(reader); var messageContent = record.Content; var headers = DeserializeHeaders(record.Headers); var message = new Message(headers, messageContent); #pragma warning disable 612 var principal = await ResolvePrincipal(headers, record.SenderPrincipal); #pragma warning restore 612 var attempts = record.Attempts; var queuedMessage = new QueuedMessage(message, principal, attempts); queuedMessages.Add(queuedMessage); } } } scope.Complete(); } } finally { ConnectionProvider.ReleaseConnection(connection); } return(queuedMessages.AsEnumerable()); }
/// <summary> /// Inserts a new queued message into the database /// </summary> /// <param name="queuedMessage">The queued message to insert</param> /// <param name="cancellationToken">(Optional) A cancellation token through which the /// caller can request cancellation of the insert operation</param> /// <returns>Returns a task that completes when the insert operation completes</returns> protected virtual async Task InsertQueuedMessage(QueuedMessage queuedMessage, CancellationToken cancellationToken = default(CancellationToken)) { var message = queuedMessage.Message; var principal = queuedMessage.Principal; var expires = message.Headers.Expires; var connection = ConnectionProvider.GetConnection(); var securityToken = await SecurityTokenService.NullSafeIssue(principal, expires); var persistedMessage = message.WithSecurityToken(securityToken); if (MessageEncryptionService != null) { persistedMessage = await MessageEncryptionService.Encrypt(message); } try { var headers = persistedMessage.Headers; var commandBuilder = CommandBuilders.NewInsertQueuedMessageCommandBuilder(); commandBuilder.MessageId = headers.MessageId; commandBuilder.QueueName = QueueName; commandBuilder.Origination = headers.Origination?.ToString(); commandBuilder.Destination = headers.Destination?.ToString(); commandBuilder.ReplyTo = headers.ReplyTo?.ToString(); commandBuilder.Expires = headers.Expires; commandBuilder.ContentType = headers.ContentType; commandBuilder.Headers = SerializeHeaders(headers); commandBuilder.Content = persistedMessage.Content; using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled)) { using (var command = commandBuilder.BuildDbCommand(connection)) { await command.ExecuteNonQueryAsync(cancellationToken); } scope.Complete(); } } finally { ConnectionProvider.ReleaseConnection(connection); } }
/// <inheritdoc /> public override Task Init(CancellationToken cancellationToken = default(CancellationToken)) { // A separate database file is created for each queue, so the object initialization // commands must be done once for each queue. var conection = ConnectionProvider.GetConnection(); try { var commandBuilder = CommandBuilders.NewCreateObjectsCommandBuilder(); using (var command = commandBuilder.BuildDbCommand(conection)) { command.ExecuteNonQuery(); } } finally { ConnectionProvider.ReleaseConnection(conection); } return(base.Init(cancellationToken)); }