public ReplyHandlerStep(ConcurrentDictionary<string, TimedMessage> messages, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory, TimeSpan replyMaxAge) { _messages = messages; _replyMaxAge = replyMaxAge; _log = rebusLoggerFactory.GetCurrentClassLogger(); _cleanupTask = asyncTaskFactory.Create("CleanupAbandonedRepliesTask", CleanupAbandonedReplies); }
public ReplyHandlerStep(ConcurrentDictionary <string, TimedMessage> messages, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory, TimeSpan replyMaxAge) { _messages = messages ?? throw new ArgumentNullException(nameof(messages)); _log = rebusLoggerFactory?.GetLogger <ReplyHandlerStep>() ?? throw new ArgumentNullException(nameof(rebusLoggerFactory)); _cleanupTask = asyncTaskFactory?.Create("CleanupAbandonedRepliesTask", CleanupAbandonedReplies) ?? throw new ArgumentNullException(nameof(asyncTaskFactory)); _replyMaxAge = replyMaxAge; }
/// <summary> /// Constructs the in-mem error tracker with the configured number of delivery attempts as the MAX /// </summary> public InMemErrorTracker(int maxDeliveryAttempts, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { if (rebusLoggerFactory == null) throw new ArgumentNullException(nameof(rebusLoggerFactory)); if (asyncTaskFactory == null) throw new ArgumentNullException(nameof(asyncTaskFactory)); _maxDeliveryAttempts = maxDeliveryAttempts; _log = rebusLoggerFactory.GetCurrentClassLogger(); _cleanupOldTrackedErrorsTask = asyncTaskFactory.Create(BackgroundTaskName, CleanupOldTrackedErrors, intervalSeconds: 60); }
/// <summary> /// Constructs the step, using the specified <see cref="ITimeoutManager"/> to defer relevant messages /// and the specified <see cref="ITransport"/> to deliver messages when they're due. /// </summary> public HandleDeferredMessagesStep(ITimeoutManager timeoutManager, ITransport transport, Options options, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { _timeoutManager = timeoutManager; _transport = transport; _options = options; _log = rebusLoggerFactory.GetCurrentClassLogger(); _dueMessagesSenderBackgroundTask = asyncTaskFactory.Create(DueMessagesSenderTaskName, TimerElapsed, intervalSeconds: 1); }
/// <summary> /// Constructs the transport with the given <see cref="IDbConnectionProvider"/>, using the specified <paramref name="tableName"/> to send/receive messages, /// querying for messages with recipient = <paramref name="inputQueueName"/> /// </summary> public SqlServerTransport(IDbConnectionProvider connectionProvider, string tableName, string inputQueueName, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { _connectionProvider = connectionProvider; _tableName = tableName; _inputQueueName = inputQueueName; _log = rebusLoggerFactory.GetCurrentClassLogger(); ExpiredMessagesCleanupInterval = DefaultExpiredMessagesCleanupInterval; _expiredMessagesCleanupTask = asyncTaskFactory.Create("ExpiredMessagesCleanup", PerformExpiredMessagesCleanupCycle, intervalSeconds: 60); }
/// <summary> /// Constructs the in-mem error tracker with the configured number of delivery attempts as the MAX /// </summary> public InMemErrorTracker(int maxDeliveryAttempts, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } _maxDeliveryAttempts = maxDeliveryAttempts; _log = rebusLoggerFactory.GetLogger <InMemErrorTracker>(); _cleanupOldTrackedErrorsTask = asyncTaskFactory.Create(BackgroundTaskName, CleanupOldTrackedErrors, intervalSeconds: 60); }
IAsyncTask CreateRenewalTaskForMessage(Message message, IAmazonSQS client) { return(_asyncTaskFactory.Create($"RenewPeekLock-{message.MessageId}", async() => { _log.Info("Renewing peek lock for message with ID {messageId}", message.MessageId); var request = new ChangeMessageVisibilityRequest(_queueUrl, message.ReceiptHandle, (int)_peekLockDuration.TotalSeconds); await client.ChangeMessageVisibilityAsync(request); }, intervalSeconds: (int)_peekLockRenewalInterval.TotalSeconds, prettyInsignificant: true)); }
/// <summary> /// Constructs a MySql transport. /// </summary> public MySqlTransport(MySqlConnectionHelper connectionHelper, string tableName, string inputQueueName, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory, IRebusTime rebusTime) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } _connectionHelper = connectionHelper; _tableName = tableName; _inputQueueName = inputQueueName; _asyncTaskFactory = asyncTaskFactory ?? throw new ArgumentNullException(nameof(asyncTaskFactory)); _rebusTime = rebusTime ?? throw new ArgumentNullException(nameof(rebusTime)); ExpiredMessagesCleanupInterval = DefaultExpiredMessagesCleanupInterval; _expiredMessagesCleanupTask = asyncTaskFactory.Create("ExpiredMessagesCleanup", PerformExpiredMessagesCleanupCycle, intervalSeconds: 60); _log = rebusLoggerFactory.GetLogger <MySqlTransport>(); }
public AutoScaler(ITransport transport, IRebusLoggerFactory rebusLoggerFactory, int maximumNumberOfWorkers, IAsyncTaskFactory asyncTaskFactory, Func <IBus> busFactory, int adjustmentIntervalSeconds) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } _logger = rebusLoggerFactory.GetLogger <AutoScaler>(); _transport = transport ?? throw new ArgumentNullException(nameof(transport)); _maximumNumberOfWorkers = maximumNumberOfWorkers; _busFactory = busFactory ?? throw new ArgumentNullException(nameof(busFactory)); _task = asyncTaskFactory.Create("AutoScale", Tick, intervalSeconds: adjustmentIntervalSeconds); }
/// <summary> /// Constructs the transport, connecting to the service bus pointed to by the connection string. /// </summary> public AzureServiceBusTransport(string connectionString, string queueName, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory, INameFormatter nameFormatter, CancellationToken cancellationToken = default(CancellationToken), ITokenProvider tokenProvider = null) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } _nameFormatter = nameFormatter; if (queueName != null) { // this never happens if (queueName.StartsWith(MagicSubscriptionPrefix)) { throw new ArgumentException($"Sorry, but the queue name '{queueName}' cannot be used because it conflicts with Rebus' internally used 'magic subscription prefix': '{MagicSubscriptionPrefix}'. "); } Address = _nameFormatter.FormatQueueName(queueName); _subscriptionName = _nameFormatter.FormatSubscriptionName(queueName); } _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); _cancellationToken = cancellationToken; _log = rebusLoggerFactory.GetLogger <AzureServiceBusTransport>(); if (tokenProvider != null) { var connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString); _managementClient = new ManagementClient(connectionStringBuilder, tokenProvider); _endpoint = connectionStringBuilder.Endpoint; _transportType = connectionStringBuilder.TransportType; } else { _managementClient = new ManagementClient(connectionString); } _tokenProvider = tokenProvider; _messageLockRenewalTask = asyncTaskFactory.Create("Peek Lock Renewal", RenewPeekLocks, prettyInsignificant: true, intervalSeconds: 10); }
/// <summary> /// Constructor /// </summary> /// <param name="connectionProvider">A <see cref="IDbConnection"/> to obtain a database connection</param> /// <param name="inputQueueName">Name of the queue this transport is servicing</param> /// <param name="rebusLoggerFactory">A <seealso cref="IRebusLoggerFactory"/> for building loggers</param> /// <param name="asyncTaskFactory">A <seealso cref="IAsyncTaskFactory"/> for creating periodic tasks</param> /// <param name="rebusTime">A <seealso cref="IRebusTime"/> to provide the current time</param> /// <param name="options">Additional options</param> public MySqlTransport( IDbConnectionProvider connectionProvider, string inputQueueName, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory, IRebusTime rebusTime, MySqlTransportOptions options) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } _rebusTime = rebusTime ?? throw new ArgumentNullException(nameof(rebusTime)); _connectionProvider = connectionProvider ?? throw new ArgumentNullException(nameof(connectionProvider)); _receiveTableName = inputQueueName != null?TableName.Parse(inputQueueName) : null; _log = rebusLoggerFactory.GetLogger <MySqlTransport>(); var cleanupInterval = options.ExpiredMessagesCleanupInterval ?? DefaultExpiredMessagesCleanupInterval; var intervalSeconds = (int)cleanupInterval.TotalSeconds; _expiredMessagesCleanupTask = asyncTaskFactory.Create("ExpiredMessagesCleanup", PerformExpiredMessagesCleanupCycle, intervalSeconds: intervalSeconds); _autoDeleteQueue = options.AutoDeleteQueue; _leasedByFactory = options.LeasedByFactory ?? (() => Environment.MachineName); _leaseInterval = options.LeaseInterval ?? DefaultLeaseTime; _leaseTolerance = options.LeaseInterval ?? DefaultLeaseTolerance; _ensureTablesAreCreated = options.EnsureTablesAreCreated; var automaticLeaseRenewalInterval = options.LeaseAutoRenewInterval; if (!automaticLeaseRenewalInterval.HasValue) { _automaticLeaseRenewal = false; } else { _automaticLeaseRenewal = true; _automaticLeaseRenewalInterval = automaticLeaseRenewalInterval.Value; } }
/// <summary> /// Constructs the step, using the specified <see cref="ITimeoutManager"/> to defer relevant messages /// and the specified <see cref="ITransport"/> to deliver messages when they're due. /// </summary> public HandleDeferredMessagesStep(ITimeoutManager timeoutManager, ITransport transport, Options options, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { if (timeoutManager == null) throw new ArgumentNullException(nameof(timeoutManager)); if (transport == null) throw new ArgumentNullException(nameof(transport)); if (options == null) throw new ArgumentNullException(nameof(options)); if (rebusLoggerFactory == null) throw new ArgumentNullException(nameof(rebusLoggerFactory)); if (asyncTaskFactory == null) throw new ArgumentNullException(nameof(asyncTaskFactory)); _timeoutManager = timeoutManager; _transport = transport; _options = options; _log = rebusLoggerFactory.GetCurrentClassLogger(); var dueTimeoutsPollIntervalSeconds = (int)options.DueTimeoutsPollInterval.TotalSeconds; var intervalToUse = dueTimeoutsPollIntervalSeconds >= 1 ? dueTimeoutsPollIntervalSeconds : 1; _dueMessagesSenderBackgroundTask = asyncTaskFactory.Create(DueMessagesSenderTaskName, TimerElapsed, intervalSeconds: intervalToUse); }
/// <summary> /// Constructs the step, using the specified <see cref="ITimeoutManager"/> to defer relevant messages /// and the specified <see cref="ITransport"/> to deliver messages when they're due. /// </summary> public HandleDeferredMessagesStep(ITimeoutManager timeoutManager, ITransport transport, Options options, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } _timeoutManager = timeoutManager ?? throw new ArgumentNullException(nameof(timeoutManager)); _transport = transport ?? throw new ArgumentNullException(nameof(transport)); _options = options ?? throw new ArgumentNullException(nameof(options)); _log = rebusLoggerFactory.GetLogger <HandleDeferredMessagesStep>(); _dueMessagesSenderBackgroundTask = asyncTaskFactory.Create(DueMessagesSenderTaskName, TimerElapsed, interval: options.DueTimeoutsPollInterval); }
/// <summary> /// Constructs the transport with the given <see cref="IDbConnectionProvider"/> /// </summary> public SqlServerTransport(IDbConnectionProvider connectionProvider, string inputQueueName, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } ConnectionProvider = connectionProvider ?? throw new ArgumentNullException(nameof(connectionProvider)); ReceiveTableName = inputQueueName != null?TableName.Parse(inputQueueName) : null; _log = rebusLoggerFactory.GetLogger <SqlServerTransport>(); ExpiredMessagesCleanupInterval = DefaultExpiredMessagesCleanupInterval; _expiredMessagesCleanupTask = asyncTaskFactory.Create("ExpiredMessagesCleanup", PerformExpiredMessagesCleanupCycle, intervalSeconds: 60); }
IDisposable GetRenewalTaskOrFakeDisposable(string messageId, BrokeredMessage brokeredMessage, TimeSpan lockRenewalInterval) { if (AutomaticallyRenewPeekLock) { var renewalTask = _asyncTaskFactory.Create($"RenewPeekLock-{messageId}", async() => { _log.Info("Renewing peek lock for message with ID {0}", messageId); await brokeredMessage.RenewLockAsync(); }, intervalSeconds: (int)lockRenewalInterval.TotalSeconds, prettyInsignificant: true); renewalTask.Start(); return(renewalTask); } return(new FakeDisposable()); }
/// <summary> /// Constructs the in-mem error tracker with the configured number of delivery attempts as the MAX /// </summary> public InMemErrorTracker(SimpleRetryStrategySettings simpleRetryStrategySettings, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory, ITransport transport) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } _simpleRetryStrategySettings = simpleRetryStrategySettings ?? throw new ArgumentNullException(nameof(simpleRetryStrategySettings)); _transport = transport ?? throw new ArgumentNullException(nameof(transport)); _log = rebusLoggerFactory.GetLogger <InMemErrorTracker>(); _cleanupOldTrackedErrorsTask = asyncTaskFactory.Create( BackgroundTaskName, CleanupOldTrackedErrors, intervalSeconds: 10 ); }
/// <summary> /// Constructs the transport with the given <see cref="IDbConnectionProvider"/> /// </summary> public MySqlTransport(IDbConnectionProvider connectionProvider, string inputQueueName, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory, IRebusTime rebusTime, MySqlTransportOptions options) { if (rebusLoggerFactory == null) { throw new ArgumentNullException(nameof(rebusLoggerFactory)); } if (asyncTaskFactory == null) { throw new ArgumentNullException(nameof(asyncTaskFactory)); } _rebusTime = rebusTime ?? throw new ArgumentNullException(nameof(rebusTime)); _connectionProvider = connectionProvider ?? throw new ArgumentNullException(nameof(connectionProvider)); _receiveTableName = inputQueueName != null?TableName.Parse(inputQueueName) : null; _log = rebusLoggerFactory.GetLogger <MySqlTransport>(); var cleanupInterval = options.ExpiredMessagesCleanupInterval ?? DefaultExpiredMessagesCleanupInterval; var intervalSeconds = (int)cleanupInterval.TotalSeconds; _expiredMessagesCleanupTask = asyncTaskFactory.Create("ExpiredMessagesCleanup", PerformExpiredMessagesCleanupCycle, intervalSeconds: intervalSeconds); _autoDeleteQueue = options.AutoDeleteQueue; }
/// <summary> /// Receives the next message from the input queue. Returns null if no message was available /// </summary> public async Task <TransportMessage> Receive(ITransactionContext context, CancellationToken cancellationToken) { var receivedMessage = await ReceiveInternal().ConfigureAwait(false); if (receivedMessage == null) { return(null); } var message = receivedMessage.Message; var messageReceiver = receivedMessage.MessageReceiver; if (!message.SystemProperties.IsLockTokenSet) { throw new RebusApplicationException($"OMG that's weird - message with ID {message.MessageId} does not have a lock token!"); } var lockToken = message.SystemProperties.LockToken; var messageId = message.MessageId; if (AutomaticallyRenewPeekLock && !_prefetchingEnabled) { var now = DateTime.UtcNow; var leaseDuration = message.SystemProperties.LockedUntilUtc - now; var lockRenewalInterval = TimeSpan.FromMinutes(0.5 * leaseDuration.TotalMinutes); var cancellationTokenSource = new CancellationTokenSource(); var renewalTask = _asyncTaskFactory .Create(description: $"RenewPeekLock-{messageId}", action: () => RenewPeekLock(messageReceiver, messageId, lockToken, cancellationTokenSource), intervalSeconds: (int)lockRenewalInterval.TotalSeconds, prettyInsignificant: true ); // be sure to stop the renewal task regardless of whether we're committing or aborting context.OnCommitted(async() => renewalTask.Dispose()); context.OnAborted(() => renewalTask.Dispose()); context.OnDisposed(() => { renewalTask.Dispose(); cancellationTokenSource.Dispose(); }); cancellationTokenSource.Token.Register(renewalTask.Dispose); renewalTask.Start(); } context.OnCompleted(async() => { try { await messageReceiver.CompleteAsync(lockToken).ConfigureAwait(false); } catch (Exception exception) { throw new RebusApplicationException(exception, $"Could not complete message with ID {message.MessageId} and lock token {lockToken}"); } }); context.OnAborted(() => { try { AsyncHelpers.RunSync(async() => await messageReceiver.AbandonAsync(lockToken).ConfigureAwait(false)); } catch (Exception exception) { throw new RebusApplicationException(exception, $"Could not abandon message with ID {message.MessageId} and lock token {lockToken}"); } }); var userProperties = message.UserProperties; var headers = userProperties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToString()); var body = message.Body; return(new TransportMessage(headers, body)); }
/// <summary> /// Constructs the in-mem error tracker with the configured number of delivery attempts as the MAX /// </summary> public InMemErrorTracker(int maxDeliveryAttempts, IRebusLoggerFactory rebusLoggerFactory, IAsyncTaskFactory asyncTaskFactory) { _maxDeliveryAttempts = maxDeliveryAttempts; _log = rebusLoggerFactory.GetCurrentClassLogger(); _cleanupOldTrackedErrorsTask = asyncTaskFactory.Create(BackgroundTaskName, CleanupOldTrackedErrors, intervalSeconds: 60); }
/// <summary> /// Receives the next message from the input queue. Returns null if no message was available /// </summary> public async Task <TransportMessage> Receive(ITransactionContext context, CancellationToken cancellationToken) { var receivedMessage = await ReceiveInternal().ConfigureAwait(false); if (receivedMessage == null) { return(null); } var message = receivedMessage.Message; var messageReceiver = receivedMessage.MessageReceiver; if (!message.SystemProperties.IsLockTokenSet) { throw new RebusApplicationException($"OMG that's weird - message with ID {message.MessageId} does not have a lock token!"); } var lockToken = message.SystemProperties.LockToken; var messageId = message.MessageId; CancellationTokenSource cancellationTokenSource = null; IAsyncTask renewalTask = null; if (AutomaticallyRenewPeekLock && !_prefetchingEnabled) { var now = DateTime.UtcNow; var leaseDuration = message.SystemProperties.LockedUntilUtc - now; var lockRenewalInterval = TimeSpan.FromMinutes(0.5 * leaseDuration.TotalMinutes); cancellationTokenSource = new CancellationTokenSource(); renewalTask = _asyncTaskFactory .Create(description: $"RenewPeekLock-{messageId}", action: () => RenewPeekLock(messageReceiver, messageId, lockToken, cancellationTokenSource), intervalSeconds: (int)lockRenewalInterval.TotalSeconds, prettyInsignificant: true ); cancellationTokenSource.Token.Register(renewalTask.Dispose); renewalTask.Start(); } context.OnCompleted(async ctx => { try { await messageReceiver.CompleteAsync(lockToken).ConfigureAwait(false); } catch (Exception exception) { throw new RebusApplicationException(exception, $"Could not complete message with ID {message.MessageId} and lock token {lockToken}"); } // Dispose the renewal task after the message has been removed. // Note that we could get a MessageLockLostException and log an error in RenewPeekLock in the off chance that renewal runs between CompleteAsync and Dispose here, // but that's better than disposing the renewal first and potentially loosing the lock before calling complete. renewalTask?.Dispose(); }); context.OnAborted(async ctx => { // Dispose the renewal before abandoning the message, otherwise renewal could grab the lock again. renewalTask?.Dispose(); try { await messageReceiver.AbandonAsync(lockToken).ConfigureAwait(false); } catch (Exception exception) { throw new RebusApplicationException(exception, $"Could not abandon message with ID {message.MessageId} and lock token {lockToken}"); } }); context.OnDisposed(ctx => { renewalTask?.Dispose(); cancellationTokenSource?.Dispose(); }); var userProperties = message.UserProperties; var headers = userProperties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToString()); var body = message.Body; return(new TransportMessage(headers, body)); }