/// <summary> /// Initializes a new instance of the <see cref="CommandProcessor"/> class. /// Use this constructor when both rpc support is required /// </summary> /// <param name="subscriberRegistry">The subscriber registry.</param> /// <param name="handlerFactory">The handler factory.</param> /// <param name="requestContextFactory">The request context factory.</param> /// <param name="policyRegistry">The policy registry.</param> /// <param name="mapperRegistry">The mapper registry.</param> /// <param name="outBox">The outbox</param> /// <param name="producerRegistry">The register of producers via whom we send messages over the external bus</param> /// <param name="replySubscriptions">The Subscriptions for creating the reply queues</param> /// <param name="responseChannelFactory">If we are expecting a response, then we need a channel to listen on</param> /// <param name="outboxTimeout">How long should we wait to write to the outbox</param> /// <param name="featureSwitchRegistry">The feature switch config provider.</param> /// <param name="inboxConfiguration">Do we want to insert an inbox handler into pipelines without the attribute. Null (default = no), yes = how to configure</param> /// <param name="boxTransactionConnectionProvider">The Box Connection Provider to use when Depositing into the outbox.</param> public CommandProcessor( IAmASubscriberRegistry subscriberRegistry, IAmAHandlerFactory handlerFactory, IAmARequestContextFactory requestContextFactory, IPolicyRegistry <string> policyRegistry, IAmAMessageMapperRegistry mapperRegistry, IAmAnOutbox <Message> outBox, IAmAProducerRegistry producerRegistry, IEnumerable <Subscription> replySubscriptions, int outboxTimeout = 300, IAmAFeatureSwitchRegistry featureSwitchRegistry = null, IAmAChannelFactory responseChannelFactory = null, InboxConfiguration inboxConfiguration = null, IAmABoxTransactionConnectionProvider boxTransactionConnectionProvider = null) : this(subscriberRegistry, handlerFactory, requestContextFactory, policyRegistry) { _mapperRegistry = mapperRegistry; _featureSwitchRegistry = featureSwitchRegistry; _responseChannelFactory = responseChannelFactory; _inboxConfiguration = inboxConfiguration; _boxTransactionConnectionProvider = boxTransactionConnectionProvider; _replySubscriptions = replySubscriptions; InitExtServiceBus(policyRegistry, outBox, outboxTimeout, producerRegistry); ConfigureCallbacks(producerRegistry); }
public async Task AddAsync(Message message, int outBoxTimeout = -1, CancellationToken cancellationToken = default(CancellationToken), IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { var parameters = InitAddDbParameters(message); var connectionProvider = _connectionProvider; if (transactionConnectionProvider != null && transactionConnectionProvider is IMySqlTransactionConnectionProvider provider) { connectionProvider = provider; } var connection = connectionProvider.GetConnection(); if (connection.State != ConnectionState.Open) { await connection.OpenAsync(cancellationToken).ConfigureAwait(ContinueOnCapturedContext); } using (var command = connection.CreateCommand()) { var sql = GetAddSql(); command.CommandText = sql; AddParamtersParamArrayToCollection(parameters.ToArray(), command); try { if (connectionProvider.IsSharedConnection) { command.Transaction = connectionProvider.GetTransaction(); } await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(ContinueOnCapturedContext); } catch (MySqlException sqlException) { if (IsExceptionUnqiueOrDuplicateIssue(sqlException)) { s_logger.LogWarning( "MsSqlOutbox: A duplicate Message with the MessageId {Id} was inserted into the Outbox, ignoring and continuing", message.Id); return; } throw; } finally { if (!connectionProvider.IsSharedConnection) { connection.Dispose(); } else if (!connectionProvider.HasOpenTransaction) { connection.Close(); } } } }
/// <summary> /// The <see cref="CommandProcessor"/> wants to support <see cref="CommandProcessor.Post{T}(T)"/> or <see cref="CommandProcessor.Repost"/> using an external bus. /// You need to provide a policy to specify how QoS issues, specifically <see cref="CommandProcessor.RETRYPOLICY "/> or <see cref="CommandProcessor.CIRCUITBREAKER "/> /// are handled by adding appropriate <see cref="Policies"/> when choosing this option. /// /// </summary> /// <param name="configuration">The Task Queues configuration.</param> /// <param name="outbox">The Outbox.</param> /// <param name="boxTransactionConnectionProvider"></param> /// <returns>INeedARequestContext.</returns> public INeedARequestContext ExternalBus(ExternalBusConfiguration configuration, IAmAnOutbox <Message> outbox, IAmABoxTransactionConnectionProvider boxTransactionConnectionProvider = null) { _useExternalBus = true; _producers = configuration.ProducerRegistry; _outbox = outbox; _overridingBoxTransactionConnectionProvider = boxTransactionConnectionProvider; _messageMapperRegistry = configuration.MessageMapperRegistry; _outboxWriteTimeout = configuration.OutboxWriteTimeout; return(this); }
internal void AddToOutbox <T>(T request, Message message, IAmABoxTransactionConnectionProvider overridingTransactionConnectionProvider = null) where T : class, IRequest { CheckOutboxOutstandingLimit(); var written = Retry(() => { OutBox.Add(message, OutboxTimeout, overridingTransactionConnectionProvider); }); if (!written) { throw new ChannelFailureException($"Could not write request {request.Id} to the outbox"); } }
/// <summary> /// Adds the specified message. /// The message must have a 'streamId' and an 'eventNumber' in the message header bag. /// The 'streamId' is the name of the stream to append the message to. /// The 'eventNumber' should be one greater than the last event in the stream. /// </summary> /// <param name="message">The message.</param> /// <param name="outBoxTimeout">The outBoxTimeout.</param> /// <returns>Task.</returns> public void Add(Message message, int outBoxTimeout = -1, IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { s_logger.LogDebug("Adding message to Event Store Outbox: {Request}", JsonSerializer.Serialize(message, JsonSerialisationOptions.Options)); var headerBag = message.Header.Bag; var streamId = ExtractStreamIdFromHeader(headerBag, message.Id); var eventNumber = ExtractEventNumberFromHeader(headerBag, message.Id); var numberOfPreviousEvent = eventNumber - 1; var eventData = EventStoreMessageWriter.CreateEventData(message); _eventStore.AppendToStreamAsync(streamId, numberOfPreviousEvent, eventData).Wait(); }
/// <summary> /// Adds the specified message. /// </summary> /// <param name="message">The message.</param> /// <param name="outBoxTimeout"></param> /// <param name="transactionConnectionProvider">Connection Provider to use for this call</param> /// <returns>Task.</returns> public void Add(Message message, int outBoxTimeout = -1, IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { var parameters = InitAddDbParameters(message); var connectionProvider = _connectionProvider; if (transactionConnectionProvider != null && transactionConnectionProvider is IMsSqlTransactionConnectionProvider provider) { connectionProvider = provider; } var connection = connectionProvider.GetConnection(); if (connection.State != ConnectionState.Open) { connection.Open(); } using (var command = InitAddDbCommand(connection, parameters)) { try { if (connectionProvider.HasOpenTransaction) { command.Transaction = connectionProvider.GetTransaction(); } command.ExecuteNonQuery(); } catch (SqlException sqlException) { if (sqlException.Number == MsSqlDuplicateKeyError_UniqueIndexViolation || sqlException.Number == MsSqlDuplicateKeyError_UniqueConstraintViolation) { s_logger.LogWarning( "MsSqlOutbox: A duplicate Message with the MessageId {Id} was inserted into the Outbox, ignoring and continuing", message.Id); return; } throw; } finally { if (!connectionProvider.IsSharedConnection) { connection.Dispose(); } else if (!connectionProvider.HasOpenTransaction) { connection.Close(); } } } }
/// <summary> /// Adds the specified message /// </summary> /// <param name="message"></param> /// <param name="outBoxTimeout"></param> /// <param name="transactionConnectionProvider">This is not used for the In Memory Outbox.</param> public void Add(Message message, int outBoxTimeout = -1, IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { ClearExpiredMessages(); EnforceCapacityLimit(); var key = OutboxEntry.ConvertKey(message.Id); if (!_requests.ContainsKey(key)) { if (!_requests.TryAdd(key, new OutboxEntry { Message = message, WriteTime = DateTime.UtcNow })) { throw new Exception($"Could not add message with Id: {message.Id} to outbox"); } } }
/// <summary> /// Adds the specified message. /// </summary> /// <param name="message">The message.</param> /// <param name="outBoxTimeout"></param> /// <returns>Task.</returns> public void Add(Message message, int outBoxTimeout = -1, IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { var parameters = InitAddDbParameters(message); var connectionProvider = _connectionProvider; if (transactionConnectionProvider != null && transactionConnectionProvider is ISqliteTransactionConnectionProvider provider) { connectionProvider = provider; } var connection = connectionProvider.GetConnection(); if (connection.State != ConnectionState.Open) { connection.Open(); } var sql = GetAddSql(); using (var command = connection.CreateCommand()) { command.CommandText = sql; AddParamtersParamArrayToCollection(parameters.ToArray(), command); try { if (connectionProvider.HasOpenTransaction) { command.Transaction = connectionProvider.GetTransaction(); } command.ExecuteNonQuery(); } catch (SqliteException sqlException) { if (IsExceptionUnqiueOrDuplicateIssue(sqlException)) { s_logger.LogWarning( "MsSqlOutbox: A duplicate Message with the MessageId {Id} was inserted into the Outbox, ignoring and continuing", message.Id); return; } throw; } } }
private IPostgreSqlConnectionProvider GetConnectionProvider(IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { var connectionProvider = _connectionProvider ?? new PostgreSqlNpgsqlConnectionProvider(_configuration); if (transactionConnectionProvider != null) { if (transactionConnectionProvider is IPostgreSqlTransactionConnectionProvider provider) { connectionProvider = provider; } else { throw new Exception($"{nameof(transactionConnectionProvider)} does not implement interface {nameof(IPostgreSqlTransactionConnectionProvider)}."); } } return(connectionProvider); }
private Guid DepositPost <T>(T request, IAmABoxTransactionConnectionProvider connectionProvider) where T : class, IRequest { s_logger.LogInformation("Save request: {RequestType} {Id}", request.GetType(), request.Id); if (!_bus.HasOutbox()) { throw new InvalidOperationException("No outbox defined."); } var messageMapper = _mapperRegistry.Get <T>(); if (messageMapper == null) { throw new ArgumentOutOfRangeException($"No message mapper registered for messages of type: {typeof(T)}"); } var message = messageMapper.MapToMessage(request); _bus.AddToOutbox(request, message, connectionProvider); return(message.Id); }
/// <summary> /// Initializes a new instance of the <see cref="CommandProcessor"/> class. /// Use this constructor when only posting messages to an external bus is required /// </summary> /// <param name="requestContextFactory">The request context factory.</param> /// <param name="policyRegistry">The policy registry.</param> /// <param name="mapperRegistry">The mapper registry.</param> /// <param name="outBox">The outbox</param> /// <param name="producerRegistry">The register of producers via whom we send messages over the external bus</param> /// <param name="outboxTimeout">How long should we wait to write to the outbox</param> /// <param name="featureSwitchRegistry">The feature switch config provider.</param> /// <param name="inboxConfiguration">Do we want to insert an inbox handler into pipelines without the attribute. Null (default = no), yes = how to configure</param> /// <param name="boxTransactionConnectionProvider">The Box Connection Provider to use when Depositing into the outbox.</param> public CommandProcessor( IAmARequestContextFactory requestContextFactory, IPolicyRegistry <string> policyRegistry, IAmAMessageMapperRegistry mapperRegistry, IAmAnOutbox <Message> outBox, IAmAProducerRegistry producerRegistry, int outboxTimeout = 300, IAmAFeatureSwitchRegistry featureSwitchRegistry = null, InboxConfiguration inboxConfiguration = null, IAmABoxTransactionConnectionProvider boxTransactionConnectionProvider = null) { _requestContextFactory = requestContextFactory; _policyRegistry = policyRegistry; _mapperRegistry = mapperRegistry; _featureSwitchRegistry = featureSwitchRegistry; _inboxConfiguration = inboxConfiguration; _boxTransactionConnectionProvider = boxTransactionConnectionProvider; InitExtServiceBus(policyRegistry, outBox, outboxTimeout, producerRegistry); ConfigureCallbacks(producerRegistry); }
private async Task <Guid> DepositPostAsync <T>(T request, IAmABoxTransactionConnectionProvider connectionProvider, bool continueOnCapturedContext = false, CancellationToken cancellationToken = default(CancellationToken)) where T : class, IRequest { s_logger.LogInformation("Save request: {RequestType} {Id}", request.GetType(), request.Id); if (!_bus.HasAsyncOutbox()) { throw new InvalidOperationException("No async outbox defined."); } var messageMapper = _mapperRegistry.Get <T>(); if (messageMapper == null) { throw new ArgumentOutOfRangeException($"No message mapper registered for messages of type: {typeof(T)}"); } var message = messageMapper.MapToMessage(request); await _bus.AddToOutboxAsync(request, continueOnCapturedContext, cancellationToken, message, connectionProvider); return(message.Id); }
private static INeedARequestContext AddExternalBusMaybe( IBrighterOptions options, IAmAProducerRegistry producerRegistry, INeedMessaging messagingBuilder, MessageMapperRegistry messageMapperRegistry, InboxConfiguration inboxConfiguration, IAmAnOutboxSync <Message> outbox, IAmABoxTransactionConnectionProvider overridingConnectionProvider, IUseRpc useRequestResponse) { ExternalBusType externalBusType = GetExternalBusType(producerRegistry, useRequestResponse); if (externalBusType == ExternalBusType.None) { return(messagingBuilder.NoExternalBus()); } else if (externalBusType == ExternalBusType.FireAndForget) { return(messagingBuilder.ExternalBus( new ExternalBusConfiguration(producerRegistry, messageMapperRegistry, useInbox: inboxConfiguration), outbox, overridingConnectionProvider)); } else if (externalBusType == ExternalBusType.RPC) { return(messagingBuilder.ExternalRPC( new ExternalBusConfiguration( producerRegistry, messageMapperRegistry, responseChannelFactory: options.ChannelFactory, useInbox: inboxConfiguration), outbox, useRequestResponse.ReplyQueueSubscriptions)); } throw new ArgumentOutOfRangeException("The external bus type requested was not understood"); }
public void Add(Message message, int outBoxTimeout = -1, IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { //discard message }
internal async Task AddToOutboxAsync <T>(T request, bool continueOnCapturedContext, CancellationToken cancellationToken, Message message, IAmABoxTransactionConnectionProvider overridingTransactionConnectionProvider = null) where T : class, IRequest { CheckOutboxOutstandingLimit(); var written = await RetryAsync(async ct => { await AsyncOutbox.AddAsync(message, OutboxTimeout, ct, overridingTransactionConnectionProvider).ConfigureAwait(continueOnCapturedContext); }, continueOnCapturedContext, cancellationToken).ConfigureAwait(continueOnCapturedContext); if (!written) { throw new ChannelFailureException($"Could not write request {request.Id} to the outbox"); } }
/// <summary> /// Awaitable add the specified message. /// </summary> /// <param name="message">The message.</param> /// <param name="outBoxTimeout">The time allowed for the write in milliseconds; on a -1 default</param> /// <param name="cancellationToken">Allows the sender to cancel the request pipeline. Optional</param> /// <returns><see cref="Task"/>.</returns> public async Task AddAsync(Message message, int outBoxTimeout = -1, CancellationToken cancellationToken = default(CancellationToken), IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { s_logger.LogDebug("Adding message to Event Store Outbox: {Request}", JsonSerializer.Serialize(message, JsonSerialisationOptions.Options)); var streamId = ExtractStreamIdFromHeader(message.Header.Bag, message.Id); var eventNumber = ExtractEventNumberFromHeader(message.Header.Bag, message.Id); var numberOfPreviousEvent = eventNumber - 1; var eventData = EventStoreMessageWriter.CreateEventData(message); await _eventStore.AppendToStreamAsync(streamId, numberOfPreviousEvent, eventData); }
public Task AddAsync(Message message, int outBoxTimeout = -1, CancellationToken cancellationToken = default(CancellationToken), IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled(cancellationToken)); } Add(message, outBoxTimeout); return(Task.FromResult(0)); }
public void Add(Message message, int outBoxTimeout = -1, IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { _posts.Add(new OutboxEntry { Message = message, TimeDeposited = DateTime.UtcNow }); }
/// <summary> /// Adds the specified message /// </summary> /// <param name="message"></param> /// <param name="outBoxTimeout"></param> /// <param name="cancellationToken"></param> /// <param name="transactionConnectionProvider">This is not used for the In Memory Outbox.</param> /// <returns></returns> public Task AddAsync(Message message, int outBoxTimeout = -1, CancellationToken cancellationToken = default(CancellationToken), IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { var tcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); if (cancellationToken.IsCancellationRequested) { tcs.SetCanceled(); return(tcs.Task); } Add(message, outBoxTimeout); tcs.SetResult(new object()); return(tcs.Task); }
/// <inheritdoc /> /// <summary> /// Adds a message to the store /// </summary> /// <param name="message">The message to be stored</param> /// <param name="outBoxTimeout">Timeout in milliseconds; -1 for default timeout</param> public void Add(Message message, int outBoxTimeout = -1, IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { AddAsync(message, outBoxTimeout).ConfigureAwait(ContinueOnCapturedContext).GetAwaiter().GetResult(); }
/// <inheritdoc /> /// <summary> /// Adds a message to the store /// </summary> /// <param name="message">The message to be stored</param> /// <param name="outBoxTimeout">Timeout in milliseconds; -1 for default timeout</param> /// <param name="cancellationToken">Allows the sender to cancel the request pipeline. Optional</param> public async Task AddAsync(Message message, int outBoxTimeout = -1, CancellationToken cancellationToken = default(CancellationToken), IAmABoxTransactionConnectionProvider transactionConnectionProvider = null) { var messageToStore = new MessageItem(message); await _context.SaveAsync( messageToStore, new DynamoDBOperationConfig { OverrideTableName = _configuration.TableName }, cancellationToken) .ConfigureAwait(ContinueOnCapturedContext); }