/// <summary> /// Returns the next message, if any. /// </summary> /// <param name="context">The context.</param> /// <param name="connectionHolder">The connection.</param> /// <param name="noMessageFoundActon">The no message found action.</param> /// <param name="routes">The routes.</param> /// <returns> /// A message if one is found; null otherwise /// </returns> public async Task <IReceivedMessageInternal> GetMessageAsync(IMessageContext context, IConnectionHolder <NpgsqlConnection, NpgsqlTransaction, NpgsqlCommand> connectionHolder, Action <IConnectionHolder <NpgsqlConnection, NpgsqlTransaction, NpgsqlCommand> > noMessageFoundActon, List <string> routes) { //if stopping, exit now if (_cancelToken.Tokens.Any(t => t.IsCancellationRequested)) { noMessageFoundActon(connectionHolder); return(null); } //ask for the next message, or a specific message if we have a messageID var receivedTransportMessage = await _receiveMessageAsync.Handle(new ReceiveMessageQueryAsync <NpgsqlConnection, NpgsqlTransaction>(connectionHolder.Connection, connectionHolder.Transaction, routes)).ConfigureAwait(false); return(ProcessMessage(receivedTransportMessage, connectionHolder, context, noMessageFoundActon)); }
/// <summary> /// Returns the next message, if any. /// </summary> /// <param name="context">The context.</param> /// <param name="connectionHolder">The connection.</param> /// <param name="noMessageFoundActon">The no message found action.</param> /// <param name="routes">The routes.</param> /// <returns> /// A message if one is found; null otherwise /// </returns> public IReceivedMessageInternal GetMessage(IMessageContext context, IConnectionHolder <NpgsqlConnection, NpgsqlTransaction, NpgsqlCommand> connectionHolder, Action <IConnectionHolder <NpgsqlConnection, NpgsqlTransaction, NpgsqlCommand> > noMessageFoundActon, List <string> routes) { //if stopping, exit now if (_cancelToken.Tokens.Any(t => t.IsCancellationRequested)) { noMessageFoundActon(connectionHolder); return(null); } //ask for the next message var receivedTransportMessage = _receiveMessage.Handle(new ReceiveMessageQuery <NpgsqlConnection, NpgsqlTransaction>(connectionHolder.Connection, connectionHolder.Transaction, routes)); return(ProcessMessage(receivedTransportMessage, connectionHolder, context, noMessageFoundActon)); }
/// <summary> /// Returns the next message, if any. /// </summary> /// <param name="context">The context.</param> /// <param name="connectionHolder">The connection.</param> /// <param name="noMessageFoundActon">The no message found action.</param> /// <returns> /// A message if one is found; null otherwise /// </returns> public IReceivedMessageInternal GetMessage(IMessageContext context, IConnectionHolder <SqlConnection, SqlTransaction, SqlCommand> connectionHolder, Action <IConnectionHolder <SqlConnection, SqlTransaction, SqlCommand> > noMessageFoundActon) { //if stopping, exit now if (_cancelToken.Tokens.Any(t => t.IsCancellationRequested)) { noMessageFoundActon(connectionHolder); return(null); } //ask for the next message var receivedTransportMessage = _receiveMessage.Handle(new ReceiveMessageQuery <SqlConnection, SqlTransaction>(connectionHolder.Connection, connectionHolder.Transaction, _configuration.Routes)); //if no message (null) run the no message action and return if (receivedTransportMessage == null) { noMessageFoundActon(connectionHolder); return(null); } //set the message ID on the context for later usage context.SetMessageAndHeaders(receivedTransportMessage.MessageId, receivedTransportMessage.Headers); //if we are holding open transactions, we need to update the status table in a separate call //When not using held transactions, this is part of the de-queue statement and so not needed here //TODO - we could consider using a task to update the status table //the status table drives nothing internally, however it may drive external processes //because of that, we are not returning the message until the status table is updated. //we could make this a configurable option in the future? if (_configuration.Options().EnableHoldTransactionUntilMessageCommitted&& _configuration.Options().EnableStatusTable) { _setStatusCommandHandler.Handle( new SetStatusTableStatusCommand( (long)receivedTransportMessage.MessageId.Id.Value, QueueStatuses.Processing)); } return(receivedTransportMessage); }
/// <summary> /// Handles the specified command. /// </summary> /// <param name="commandSend">The command.</param> /// <returns></returns> /// <exception cref="DotNetWorkQueueException">Failed to insert record - the ID of the new record returned by SQLite was 0</exception> public async Task <long> HandleAsync(SendMessageCommand commandSend) { if (!_databaseExists.Exists(_configurationSend.ConnectionInfo.ConnectionString)) { return(0); } if (!_messageExpirationEnabled.HasValue) { _messageExpirationEnabled = _options.Value.EnableMessageExpiration; } using (var connection = _dbFactory.CreateConnection(_configurationSend.ConnectionInfo.ConnectionString, false)) { connection.Open(); var expiration = TimeSpan.Zero; if (_messageExpirationEnabled.Value) { expiration = MessageExpiration.GetExpiration(commandSend, data => data.GetExpiration()); } var jobName = _jobSchedulerMetaData.GetJobName(commandSend.MessageData); var scheduledTime = DateTimeOffset.MinValue; var eventTime = DateTimeOffset.MinValue; if (!string.IsNullOrWhiteSpace(jobName)) { scheduledTime = _jobSchedulerMetaData.GetScheduledTime(commandSend.MessageData); eventTime = _jobSchedulerMetaData.GetEventTime(commandSend.MessageData); } IDbCommand commandStatus = null; using (var command = SendMessage.GetMainCommand(commandSend, connection, _commandCache, _headers, _serializer)) { long id; using (var commandMeta = SendMessage.CreateMetaDataRecord(commandSend.MessageData.GetDelay(), expiration, connection, commandSend.MessageToSend, commandSend.MessageData, _tableNameHelper, _headers, _options.Value, _getTime)) { if (_options.Value.EnableStatusTable) { commandStatus = CreateStatusRecord(connection, commandSend.MessageToSend, commandSend.MessageData); } using (var trans = _dbFactory.CreateTransaction(connection).BeginTransaction()) { try { if (string.IsNullOrWhiteSpace(jobName) || _jobExistsHandler.Handle(new DoesJobExistQuery <IDbConnection, IDbTransaction>(jobName, scheduledTime, connection, trans)) == QueueStatuses.NotQueued) { command.Transaction = trans; await _readerAsync.ExecuteNonQueryAsync(command).ConfigureAwait(false); var commandId = connection.CreateCommand(); commandId.Transaction = trans; commandId.CommandText = "SELECT last_insert_rowid();"; id = Convert.ToInt64(await _readerAsync.ExecuteScalarAsync(commandId).ConfigureAwait(false)); if (id > 0) { commandMeta.Transaction = trans; var param = commandMeta.CreateParameter(); param.ParameterName = "@QueueID"; param.DbType = DbType.Int64; param.Value = id; commandMeta.Parameters.Add(param); await _readerAsync.ExecuteNonQueryAsync(commandMeta).ConfigureAwait(false); if (commandStatus != null) { commandStatus.Transaction = trans; param = commandStatus.CreateParameter(); param.ParameterName = "@QueueID"; param.DbType = DbType.Int64; param.Value = id; commandStatus.Parameters.Add(param); await _readerAsync.ExecuteNonQueryAsync(commandStatus).ConfigureAwait(false); } if (!string.IsNullOrWhiteSpace(jobName)) { _sendJobStatus.Handle(new SetJobLastKnownEventCommand <IDbConnection, IDbTransaction>(jobName, eventTime, scheduledTime, connection, trans)); } trans.Commit(); } else { throw new DotNetWorkQueueException( "Failed to insert record - the ID of the new record returned by SQLite was 0"); } } else { throw new DotNetWorkQueueException( "Failed to insert record - the job has already been queued or processed"); } } finally { commandStatus?.Dispose(); } } } return(id); } } }
/// <inheritdoc /> public async Task <long> HandleAsync(SendMessageCommand commandSend) { if (!_messageExpirationEnabled.HasValue) { _messageExpirationEnabled = _options.Value.EnableMessageExpiration; } var jobName = _jobSchedulerMetaData.GetJobName(commandSend.MessageData); var scheduledTime = DateTimeOffset.MinValue; var eventTime = DateTimeOffset.MinValue; if (!string.IsNullOrWhiteSpace(jobName)) { scheduledTime = _jobSchedulerMetaData.GetScheduledTime(commandSend.MessageData); eventTime = _jobSchedulerMetaData.GetEventTime(commandSend.MessageData); } using (var connection = new NpgsqlConnection(_configurationSend.ConnectionInfo.ConnectionString)) { connection.Open(); using (var trans = connection.BeginTransaction()) { if (string.IsNullOrWhiteSpace(jobName) || _jobExistsHandler.Handle(new DoesJobExistQuery <NpgsqlConnection, NpgsqlTransaction>(jobName, scheduledTime, connection, trans)) == QueueStatuses.NotQueued) { using (var command = connection.CreateCommand()) { command.CommandText = _commandCache.GetCommand(CommandStringTypes.InsertMessageBody); command.Transaction = trans; var serialization = _serializer.Serializer.MessageToBytes(new MessageBody { Body = commandSend.MessageToSend.Body }, commandSend.MessageToSend.Headers); command.Parameters.Add("@body", NpgsqlDbType.Bytea, -1); command.Parameters["@body"].Value = serialization.Output; commandSend.MessageToSend.SetHeader(_headers.StandardHeaders.MessageInterceptorGraph, serialization.Graph); command.Parameters.Add("@headers", NpgsqlDbType.Bytea, -1); command.Parameters["@headers"].Value = _serializer.InternalSerializer.ConvertToBytes(commandSend.MessageToSend.Headers); var id = Convert.ToInt64(await command.ExecuteScalarAsync().ConfigureAwait(false)); if (id > 0) { var expiration = TimeSpan.Zero; if (_messageExpirationEnabled.Value) { expiration = MessageExpiration.GetExpiration(commandSend, data => data.GetExpiration()); } await CreateMetaDataRecordAsync(commandSend.MessageData.GetDelay(), expiration, connection, id, commandSend.MessageToSend, commandSend.MessageData, trans, _getTime.GetCurrentUtcDate()).ConfigureAwait(false); if (_options.Value.EnableStatusTable) { await CreateStatusRecordAsync(connection, id, commandSend.MessageToSend, commandSend.MessageData, trans).ConfigureAwait(false); } if (!string.IsNullOrWhiteSpace(jobName)) { _sendJobStatus.Handle(new SetJobLastKnownEventCommand <NpgsqlConnection, NpgsqlTransaction>(jobName, eventTime, scheduledTime, connection, trans)); } } else { throw new DotNetWorkQueueException( "Failed to insert record - the ID of the new record returned by the server was 0"); } trans.Commit(); return(id); } } throw new DotNetWorkQueueException( "Failed to insert record - the job has already been queued or processed"); } } }