Exemple #1
0
        public async Task Should_handle_from_service_bus_queue()
        {
            var fakeHandler = A.Fake <ITestPumpCallback>();

            A.CallTo(() => fakeHandler.Handle(A <TransportMessage> .Ignored, A <IEndpoint> .Ignored)).Returns(Task.CompletedTask);

            var pump = new AzureServiceBusMessagePump(fakeHandler.Handle, IntegrationTestFixture.QueueEndpoint,
                                                      null, new AzureServiceBusMessagePumpSettings()
            {
                MaxConcurrentHandlers       = 1,
                MaxCompletionImmediateRetry = 1
            });
            await pump.StartAsync(CancellationToken.None);

            var message = new TestMessage()
            {
                Id          = Guid.NewGuid(),
                Description = "Test Handle Queue",
                MessageDate = DateTime.Now,
                Name        = "Queue",
            };
            var messageBytes = IntegrationTestFixture.Serialize(message);
            await IntegrationTestFixture.WriteToQueue(IntegrationTestFixture.QueueEndpoint, message.MessageType, messageBytes, null);

            await Task.Delay(3000);

            A.CallTo(() => fakeHandler.Handle(
                         A <TransportMessage> .That.Matches(x =>
                                                            x.MessageTypeIdentifier.Equals(message.MessageType) &&
                                                            x.Data.SequenceEqual(messageBytes)
                                                            ),
                         A <IEndpoint> .That.Matches(x => x.Equals(IntegrationTestFixture.QueueEndpoint))
                         )).MustHaveHappenedOnceOrMore();
            await pump.StopAsync();
        }
Exemple #2
0
        /// <summary>
        /// Adds a background job to the <see cref="IServiceCollection"/> to automatically restart a <see cref="AzureServiceBusMessagePump"/> with a specific <paramref name="jobId"/>
        /// when the Azure Key Vault secret that holds the Azure Service Bus connection string was updated.
        /// </summary>
        /// <param name="services">The collection of services to add the job to.</param>
        /// <param name="jobId">The unique background job ID to identify which message pump to restart.</param>
        /// <param name="subscriptionNamePrefix">The name of the Azure Service Bus subscription that will be created to receive <see cref="CloudEvent"/>'s.</param>
        /// <param name="serviceBusTopicConnectionStringSecretKey">The secret key that points to the Azure Service Bus Topic connection string.</param>
        /// <param name="messagePumpConnectionStringKey">
        ///     The secret key where the connection string credentials are located for the target message pump that needs to be auto-restarted.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown when the <paramref name="services"/> or the searched for <see cref="AzureServiceBusMessagePump"/> based on the given <paramref name="jobId"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///     Thrown when the <paramref name="subscriptionNamePrefix"/> or <paramref name="serviceBusTopicConnectionStringSecretKey"/> is blank.
        /// </exception>
        public static IServiceCollection AddAutoRestartServiceBusMessagePumpOnRotatedCredentialsBackgroundJob(
            this IServiceCollection services,
            string jobId,
            string subscriptionNamePrefix,
            string serviceBusTopicConnectionStringSecretKey,
            string messagePumpConnectionStringKey)
        {
            Guard.NotNull(services, nameof(services), "Requires a collection of services to add the re-authentication background job");
            Guard.NotNullOrWhitespace(jobId, nameof(jobId), "Requires a non-blank job ID to identify the Azure Service Bus message pump which needs to restart");
            Guard.NotNullOrWhitespace(subscriptionNamePrefix, nameof(subscriptionNamePrefix), "Requires a non-blank subscription name of the Azure Service Bus Topic subscription, to receive Azure Key Vault events");
            Guard.NotNullOrWhitespace(serviceBusTopicConnectionStringSecretKey, nameof(serviceBusTopicConnectionStringSecretKey), "Requires a non-blank secret key that points to a Azure Service Bus Topic");
            Guard.NotNullOrWhitespace(messagePumpConnectionStringKey, nameof(messagePumpConnectionStringKey), "Requires a non-blank secret key that points to the credentials that holds the connection string of the target message pump");

            services.AddCloudEventBackgroundJob(subscriptionNamePrefix, serviceBusTopicConnectionStringSecretKey);
            services.WithServiceBusMessageHandler <ReAuthenticateOnRotatedCredentialsMessageHandler, CloudEvent>(
                messageBodyFilter: cloudEvent => cloudEvent?.GetPayload <SecretNewVersionCreated>() != null,
                implementationFactory: serviceProvider =>
            {
                AzureServiceBusMessagePump messagePump =
                    serviceProvider.GetServices <IHostedService>()
                    .OfType <AzureServiceBusMessagePump>()
                    .FirstOrDefault(pump => pump.JobId == jobId);

                if (messagePump is null)
                {
                    throw new InvalidOperationException(
                        $"Cannot register re-authentication without a '{nameof(AzureServiceBusMessagePump)}' with job id {jobId}");
                }

                var messageHandlerLogger = serviceProvider.GetRequiredService <ILogger <ReAuthenticateOnRotatedCredentialsMessageHandler> >();
                return(new ReAuthenticateOnRotatedCredentialsMessageHandler(messagePumpConnectionStringKey, messagePump, messageHandlerLogger));
            });

            return(services);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ReAuthenticateOnRotatedCredentialsMessageHandler"/> class.
        /// </summary>
        /// <param name="targetConnectionStringKey">The secret key where the connection string credentials are located for the target message pump that needs to be auto-restarted.</param>
        /// <param name="messagePump">The message pump instance to restart when the message handler process an <see cref="SecretNewVersionCreated"/> event.</param>
        /// <param name="logger">The logger instance to write diagnostic trace messages during the processing of the event.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="messagePump"/> or <paramref name="logger"/> is <c>null</c>.</exception>
        public ReAuthenticateOnRotatedCredentialsMessageHandler(
            string targetConnectionStringKey,
            AzureServiceBusMessagePump messagePump,
            ILogger <ReAuthenticateOnRotatedCredentialsMessageHandler> logger)
        {
            Guard.NotNullOrWhitespace(targetConnectionStringKey, nameof(targetConnectionStringKey), "Requires a non-blank secret key that points to the credentials that holds the connection string of the target message pump");
            Guard.NotNull(messagePump, nameof(messagePump), $"Requires an message pump instance to restart when the message handler process an {nameof(SecretNewVersionCreated)} event");
            Guard.NotNull(logger, nameof(logger), "Requires an logger instance to write diagnostic trace messages during the processing of the event");

            _targetConnectionStringKey = targetConnectionStringKey;
            _messagePump = messagePump;
            _logger      = logger;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ReAuthenticateOnRotatedCredentialsMessageHandler"/> class.
 /// </summary>
 /// <param name="targetConnectionStringKey">The secret key where the connection string credentials are located for the target message pump that needs to be auto-restarted.</param>
 /// <param name="messagePump">The message pump instance to restart when the message handler process an <see cref="SecretNewVersionCreated"/> event.</param>
 /// <exception cref="ArgumentNullException">Thrown when the <paramref name="messagePump"/> is <c>null</c>.</exception>
 public ReAuthenticateOnRotatedCredentialsMessageHandler(
     string targetConnectionStringKey,
     AzureServiceBusMessagePump messagePump)
     : this(targetConnectionStringKey, messagePump, NullLogger <ReAuthenticateOnRotatedCredentialsMessageHandler> .Instance)
 {
 }
Exemple #5
0
        public async Task Should_defer_and_queue_control_message()
        {
            var fakeHandler = A.Fake <ITestPumpCallback>();

            A.CallTo(() => fakeHandler.Handle(A <TransportMessage> .Ignored, A <IEndpoint> .Ignored))
            .Throws <Exception>().Twice()
            .Then.Returns(Task.CompletedTask);

            var deferRecoverabilityProvider = new AzureServiceBusDeferRecoverabilityProvider(
                new ConstantRetryStrategy(3)
                );

            var wrappedRecoverability = A.Fake <IAzureServiceBusRecoverabilityProvider>(x => x.Wrapping(deferRecoverabilityProvider));

            var pump = new AzureServiceBusMessagePump(fakeHandler.Handle, IntegrationTestFixture.QueueEndpoint,
                                                      null, new AzureServiceBusMessagePumpSettings()
            {
                MaxConcurrentHandlers = 1,
            },
                                                      wrappedRecoverability
                                                      );

            await pump.StartAsync(CancellationToken.None);

            var message = new TestMessage()
            {
                Id          = Guid.NewGuid(),
                Description = "Test Handle Deferred Retry",
                MessageDate = DateTime.Now,
                Name        = "Queue Deferred Retry",
            };
            var messageBytes = IntegrationTestFixture.Serialize(message);
            await IntegrationTestFixture.WriteToQueue(IntegrationTestFixture.QueueEndpoint, message.MessageType, messageBytes, null);

            await Task.Delay(11000);

            ///This doesn't seem to work because the Message may be getting reused so the value changes
            ////recover should have deferred and scheduled recover control message
            //A.CallTo(() => wrappedRecoverability.OnPreHandle(
            //  A<RecoverabilityContext>.That.Matches(x =>
            //     x.Message.Label == ("ControlMessage.Recover")
            //  )
            //)).MustHaveHappenedTwiceExactly();

            //handled exception by calling recover
            A.CallTo(() => wrappedRecoverability.Recover(
                         A <RecoverabilityContext> .That.Matches(x =>
                                                                 x.Message.Body.SequenceEqual(messageBytes) &&
                                                                 x.Endpoint == IntegrationTestFixture.QueueEndpoint &&
                                                                 !x.TempData.ContainsKey("ControlMessage")
                                                                 )
                         )).MustHaveHappenedOnceExactly();

            A.CallTo(() => wrappedRecoverability.Recover(
                         A <RecoverabilityContext> .That.Matches(x =>
                                                                 x.Message.Body.SequenceEqual(messageBytes) &&
                                                                 x.Endpoint == IntegrationTestFixture.QueueEndpoint &&
                                                                 x.TempData.ContainsKey("ControlMessage")
                                                                 )
                         )).MustHaveHappenedOnceExactly();


            // should have been called 2 times with failure then again with success of deferred message
            A.CallTo(() => fakeHandler.Handle(
                         A <TransportMessage> .That.Matches(x =>
                                                            x.MessageTypeIdentifier.Equals(message.MessageType) &&
                                                            x.Data.SequenceEqual(messageBytes)
                                                            ),
                         A <IEndpoint> .That.Matches(x => x.Equals(IntegrationTestFixture.QueueEndpoint))
                         )).MustHaveHappened(3, Times.Exactly);

            await pump.StopAsync();
        }