public void when_sending_message_then_can_receive_it()
        {
            var sender = new TopicSender(this.Settings, this.Topic);
            Data data = new Data { Id = Guid.NewGuid(), Title = "Foo" };
            Data received = null;
            using (var receiver = new SubscriptionReceiver(this.Settings, this.Topic, this.Subscription))
            {
                var signal = new ManualResetEventSlim();

                receiver.Start(
                    m =>
                    {
                        received = m.GetBody<Data>();
                        signal.Set();
                        return MessageReleaseAction.CompleteMessage;
                    });

                sender.SendAsync(() => new BrokeredMessage(data));

                signal.Wait();
            }

            Assert.NotNull(received);
            Assert.Equal(data.Id, received.Id);
            Assert.Equal(data.Title, received.Title);
        }
        partial void OnCreateContainer(UnityContainer container)
        {
            var metadata = container.Resolve<IMetadataProvider>();
            var serializer = container.Resolve<ITextSerializer>();

            var commandBus = new CommandBus(new TopicSender(azureSettings.ServiceBus, Topics.Commands.Path), metadata, serializer);
            var topicSender = new TopicSender(azureSettings.ServiceBus, Topics.Events.Path);
            container.RegisterInstance<IMessageSender>(topicSender);
            var eventBus = new EventBus(topicSender, metadata, serializer);

            var commandProcessor = new CommandProcessor(new SubscriptionReceiver(azureSettings.ServiceBus, Topics.Commands.Path, Topics.Commands.Subscriptions.All), serializer);

            container.RegisterInstance<ICommandBus>(commandBus);
            container.RegisterInstance<IEventBus>(eventBus);
            container.RegisterInstance<ICommandHandlerRegistry>(commandProcessor);
            container.RegisterInstance<IProcessor>("CommandProcessor", commandProcessor);

            RegisterRepository(container);
            RegisterEventProcessors(container);

            // message log
            var messageLogAccount = CloudStorageAccount.Parse(azureSettings.MessageLog.ConnectionString);

            container.RegisterInstance<IProcessor>("EventLogger", new AzureMessageLogListener(
                new AzureMessageLogWriter(messageLogAccount, azureSettings.MessageLog.TableName),
                new SubscriptionReceiver(azureSettings.ServiceBus, Topics.Events.Path, Topics.Events.Subscriptions.Log)));

            container.RegisterInstance<IProcessor>("CommandLogger", new AzureMessageLogListener(
                new AzureMessageLogWriter(messageLogAccount, azureSettings.MessageLog.TableName),
                new SubscriptionReceiver(azureSettings.ServiceBus, Topics.Commands.Path, Topics.Commands.Subscriptions.Log)));
        }
        partial void OnCreateContainer(UnityContainer container)
        {
            var metadata = container.Resolve<IMetadataProvider>();
            var serializer = container.Resolve<ITextSerializer>();

            // blob
            var blobStorageAccount = CloudStorageAccount.Parse(azureSettings.BlobStorage.ConnectionString);
            container.RegisterInstance<IBlobStorage>(new SqlBlobStorage("BlobStorage"));

            var commandBus = new CommandBus(new TopicSender(azureSettings.ServiceBus, Topics.Commands.Path), metadata, serializer);
            var topicSender = new TopicSender(azureSettings.ServiceBus, Topics.Events.Path);
            container.RegisterInstance<IMessageSender>(topicSender);
            var eventBus = new EventBus(topicSender, metadata, serializer);

            var commandProcessor =
                new CommandProcessor(new SubscriptionReceiver(azureSettings.ServiceBus, Topics.Commands.Path, "all", false, new SubscriptionReceiverInstrumentation("all", this.instrumentationEnabled)), serializer);

            container.RegisterInstance<ICommandBus>(commandBus);

            container.RegisterInstance<IEventBus>(eventBus);
            container.RegisterInstance<IProcessor>("CommandProcessor", commandProcessor);

            RegisterRepository(container);
            RegisterEventProcessors(container);
            RegisterCommandHandlers(container, commandProcessor);
        }
        public void when_gets_transient_error_on_receive_then_retries()
        {
            var sender = new TopicSender(this.settings, this.topic);
            Data data = new Data { Id = Guid.NewGuid(), Title = "Foo" };
            Data received = null;
            using (var receiver = new TestableSubscriptionReceiver(this.settings, this.topic, this.subscription, new Incremental(3, TimeSpan.Zero, TimeSpan.Zero), new Incremental(0, TimeSpan.Zero, TimeSpan.Zero)))
            {
                var attempt = 0;
                var currentDelegate = receiver.DoReceiveMessageDelegate;
                receiver.DoReceiveMessageDelegate =
                    () =>
                    {
                        if (attempt++ < 1) { throw new TimeoutException(); }
                        return currentDelegate();
                    };

                var signal = new ManualResetEventSlim();

                receiver.MessageReceived += (o, e) =>
                {
                    received = e.Message.GetBody<Data>();
                    signal.Set();
                };

                receiver.Start();

                sender.SendAsync(() => new BrokeredMessage(data));

                Assert.True(signal.Wait(TimeSpan.FromSeconds(10)), "Test timed out");
            }

            Assert.NotNull(received);
            Assert.Equal(data.Id, received.Id);
            Assert.Equal(data.Title, received.Title);
        }
        partial void OnCreateContainer(UnityContainer container)
        {
            var metadata = container.Resolve<IMetadataProvider>();
            var serializer = container.Resolve<ITextSerializer>();

            // blob
            var blobStorageAccount = CloudStorageAccount.Parse(azureSettings.BlobStorage.ConnectionString);
            container.RegisterInstance<IBlobStorage>(new CloudBlobStorage(blobStorageAccount, azureSettings.BlobStorage.RootContainerName));

            var commandBus = new CommandBus(new TopicSender(azureSettings.ServiceBus, Topics.Commands.Path), metadata, serializer);
            var eventsTopicSender = new TopicSender(azureSettings.ServiceBus, Topics.Events.Path);
            container.RegisterInstance<IMessageSender>("events", eventsTopicSender);
            container.RegisterInstance<IMessageSender>("orders", new TopicSender(azureSettings.ServiceBus, Topics.EventsOrders.Path));
            container.RegisterInstance<IMessageSender>("seatsavailability", new TopicSender(azureSettings.ServiceBus, Topics.EventsAvailability.Path));
            var eventBus = new EventBus(eventsTopicSender, metadata, serializer);

            var sessionlessCommandProcessor =
                new CommandProcessor(new SubscriptionReceiver(azureSettings.ServiceBus, Topics.Commands.Path, Topics.Commands.Subscriptions.Sessionless, false, new SubscriptionReceiverInstrumentation(Topics.Commands.Subscriptions.Sessionless, this.instrumentationEnabled)), serializer);
            var seatsAvailabilityCommandProcessor =
                new CommandProcessor(new SessionSubscriptionReceiver(azureSettings.ServiceBus, Topics.Commands.Path, Topics.Commands.Subscriptions.Seatsavailability, false, new SessionSubscriptionReceiverInstrumentation(Topics.Commands.Subscriptions.Seatsavailability, this.instrumentationEnabled)), serializer);

            var synchronousCommandBus = new SynchronousCommandBusDecorator(commandBus);
            container.RegisterInstance<ICommandBus>(synchronousCommandBus);

            container.RegisterInstance<IEventBus>(eventBus);
            container.RegisterInstance<IProcessor>("SessionlessCommandProcessor", sessionlessCommandProcessor);
            container.RegisterInstance<IProcessor>("SeatsAvailabilityCommandProcessor", seatsAvailabilityCommandProcessor);

            RegisterRepositories(container);
            RegisterEventProcessors(container);
            RegisterCommandHandlers(container, sessionlessCommandProcessor, seatsAvailabilityCommandProcessor);

            // handle order commands inline, as they do not have competition.
            synchronousCommandBus.Register(container.Resolve<ICommandHandler>("OrderCommandHandler"));

            // message log
            var messageLogAccount = CloudStorageAccount.Parse(azureSettings.MessageLog.ConnectionString);

            container.RegisterInstance<IProcessor>("EventLogger", new AzureMessageLogListener(
                new AzureMessageLogWriter(messageLogAccount, azureSettings.MessageLog.TableName),
                new SubscriptionReceiver(azureSettings.ServiceBus, Topics.Events.Path, Topics.Events.Subscriptions.Log)));

            container.RegisterInstance<IProcessor>("OrderEventLogger", new AzureMessageLogListener(
                new AzureMessageLogWriter(messageLogAccount, azureSettings.MessageLog.TableName),
                new SubscriptionReceiver(azureSettings.ServiceBus, Topics.EventsOrders.Path, Topics.EventsOrders.Subscriptions.LogOrders)));

            container.RegisterInstance<IProcessor>("SeatsAvailabilityEventLogger", new AzureMessageLogListener(
                new AzureMessageLogWriter(messageLogAccount, azureSettings.MessageLog.TableName),
                new SubscriptionReceiver(azureSettings.ServiceBus, Topics.EventsAvailability.Path, Topics.EventsAvailability.Subscriptions.LogAvail)));

            container.RegisterInstance<IProcessor>("CommandLogger", new AzureMessageLogListener(
                new AzureMessageLogWriter(messageLogAccount, azureSettings.MessageLog.TableName),
                new SubscriptionReceiver(azureSettings.ServiceBus, Topics.Commands.Path, Topics.Commands.Subscriptions.Log)));
        }
        public void when_message_receivedthen_calls_process_message()
        {
            var waiter = new ManualResetEventSlim();
            var sender = new TopicSender(this.Settings, this.Topic);
            var processor = new FakeProcessor(
                waiter,
                new SubscriptionReceiver(this.Settings, this.Topic, this.Subscription),
                new JsonTextSerializer());

            processor.Start();

            var stream = new MemoryStream();
            new JsonTextSerializer().Serialize(new StreamWriter(stream), "Foo");
            stream.Position = 0;
            sender.SendAsync(() => new BrokeredMessage(stream, true));

            waiter.Wait(5000);

            Assert.NotNull(processor.Payload);
        }
        public void when_processing_throws_then_sends_message_to_dead_letter()
        {
            var failCount = 0;
            var waiter = new ManualResetEventSlim();
            var sender = new TopicSender(this.Settings, this.Topic);
            var processor = new Mock<MessageProcessor>(
                new SubscriptionReceiver(this.Settings, this.Topic, this.Subscription), new JsonTextSerializer()) { CallBase = true };

            processor.Protected()
                .Setup("ProcessMessage", ItExpr.IsAny<string>(), ItExpr.IsAny<object>(), ItExpr.IsAny<string>(), ItExpr.IsAny<string>())
                .Callback(() =>
                {
                    failCount++;
                    if (failCount == 5)
                        waiter.Set();

                    throw new ArgumentException();
                });

            processor.Object.Start();

            var stream = new MemoryStream();
            new JsonTextSerializer().Serialize(new StreamWriter(stream), "Foo");
            stream.Position = 0;
            sender.SendAsync(() => new BrokeredMessage(stream, true));

            waiter.Wait(5000);

            var deadReceiver = this.Settings.CreateMessageReceiver(this.Topic, this.Subscription);

            var deadMessage = deadReceiver.Receive(TimeSpan.FromSeconds(5));

            processor.Object.Dispose();

            Assert.NotNull(deadMessage);
            var data = new JsonTextSerializer().Deserialize(new StreamReader(deadMessage.GetBody<Stream>()));

            Assert.Equal("Foo", (string)data);
        }
        static partial void OnCreateContainer(UnityContainer container)
        {
            var serializer = new JsonTextSerializer();
            container.RegisterInstance<ITextSerializer>(serializer);
            var metadata = new StandardMetadataProvider();
            container.RegisterInstance<IMetadataProvider>(metadata);

            var instrumentationEnabled = CloudConfigurationManager.GetSetting("InstrumentationEnabled") == "true";

            // command bus

            var settings = InfrastructureSettings.Read(HttpContext.Current.Server.MapPath(@"~\bin\Settings.xml"));
            if (!Conference.Common.MaintenanceMode.IsInMaintainanceMode)
            {
                new ServiceBusConfig(settings.ServiceBus).Initialize();
            }
            var commandBus = new CommandBus(new TopicSender(settings.ServiceBus, "conference/commands"), metadata, serializer);

            var synchronousCommandBus = new SynchronousCommandBusDecorator(commandBus);

            container.RegisterInstance<ICommandBus>(synchronousCommandBus);
            container.RegisterInstance<ICommandHandlerRegistry>(synchronousCommandBus);

            // blob
            var blobStorageAccount = CloudStorageAccount.Parse(settings.BlobStorage.ConnectionString);
            container.RegisterInstance<IBlobStorage>(new CloudBlobStorage(blobStorageAccount, settings.BlobStorage.RootContainerName));

            // support for inline command processing

            container.RegisterType<ICommandHandler, OrderCommandHandler>("OrderCommandHandler");
            container.RegisterType<ICommandHandler, ThirdPartyProcessorPaymentCommandHandler>("ThirdPartyProcessorPaymentCommandHandler");
            container.RegisterType<ICommandHandler, SeatAssignmentsHandler>("SeatAssignmentsHandler");

            container.RegisterType<DbContext, PaymentsDbContext>("payments", new TransientLifetimeManager(), new InjectionConstructor("Payments"));
            container.RegisterType<IDataContext<ThirdPartyProcessorPayment>, SqlDataContext<ThirdPartyProcessorPayment>>(
                new TransientLifetimeManager(),
                new InjectionConstructor(new ResolvedParameter<Func<DbContext>>("payments"), typeof(IEventBus)));

            container.RegisterType<IPricingService, PricingService>(new ContainerControlledLifetimeManager());

            var topicSender = new TopicSender(settings.ServiceBus, "conference/events");
            container.RegisterInstance<IMessageSender>(topicSender);
            var eventBus = new EventBus(topicSender, metadata, serializer);

            container.RegisterInstance<IEventBus>(eventBus);

            var eventSourcingAccount = CloudStorageAccount.Parse(settings.EventSourcing.ConnectionString);
            var eventStore = new EventStore(eventSourcingAccount, settings.EventSourcing.OrdersTableName);

            container.RegisterInstance<IEventStore>(eventStore);
            container.RegisterInstance<IPendingEventsQueue>(eventStore);
            container.RegisterType<IEventStoreBusPublisher, EventStoreBusPublisher>(
                new ContainerControlledLifetimeManager(),
                new InjectionConstructor(
                    new TopicSender(settings.ServiceBus, "conference/eventsOrders"),
                    typeof(IPendingEventsQueue),
                    new EventStoreBusPublisherInstrumentation("web.public - orders", instrumentationEnabled)));
            container.RegisterType(
                typeof(IEventSourcedRepository<>),
                typeof(AzureEventSourcedRepository<>),
                new ContainerControlledLifetimeManager(),
                new InjectionConstructor(typeof(IEventStore), typeof(IEventStoreBusPublisher), typeof(ITextSerializer), typeof(IMetadataProvider), new InjectionParameter<ObjectCache>(null)));

            // to satisfy the IProcessor requirements.
            container.RegisterType<IProcessor, PublisherProcessorAdapter>("EventStoreBusPublisher", new ContainerControlledLifetimeManager());
        }
        public void when_message_fails_to_deserialize_then_dead_letters_message()
        {
            var waiter = new ManualResetEventSlim();
            var sender = new TopicSender(this.Settings, this.Topic);
            var processor = new FakeProcessor(
                waiter,
                new SubscriptionReceiver(this.Settings, this.Topic, this.Subscription),
                new JsonTextSerializer());

            processor.Start();

            var data = new JsonTextSerializer().Serialize(new Data());
            data = data.Replace(typeof(Data).FullName, "Some.TypeName.Cannot.Resolve");
            var stream = new MemoryStream(Encoding.UTF8.GetBytes(data));
            stream.Position = 0;

            sender.SendAsync(() => new BrokeredMessage(stream, true));

            waiter.Wait(5000);

            var deadReceiver = this.Settings.CreateMessageReceiver(this.Topic, this.Subscription);
            var deadMessage = deadReceiver.Receive(TimeSpan.FromSeconds(5));

            processor.Dispose();

            Assert.NotNull(deadMessage);
            var payload = new StreamReader(deadMessage.GetBody<Stream>()).ReadToEnd();

            Assert.Contains("Some.TypeName.Cannot.Resolve", payload);
        }
        public void when_gets_transient_error_several_times_on_receive_then_retries_until_failure()
        {
            var attempt = 0;
            var sender = new TopicSender(this.settings, this.topic);
            Data data = new Data { Id = Guid.NewGuid(), Title = "Foo" };
            Data received = null;
            using (var receiver = new TestableSubscriptionReceiver(this.settings, this.topic, this.subscription, new Incremental(3, TimeSpan.Zero, TimeSpan.Zero), new Incremental(0, TimeSpan.Zero, TimeSpan.Zero)))
            {
                var signal = new ManualResetEventSlim();

                receiver.DoReceiveMessageDelegate =
                    () =>
                    {
                        if (attempt++ == 3) { signal.Set(); }
                        throw new TimeoutException();
                    };

                receiver.MessageReceived += (o, e) =>
                {
                    received = e.Message.GetBody<Data>();
                };

                receiver.Start();

                sender.SendAsync(() => new BrokeredMessage(data));

                Assert.True(signal.Wait(TimeSpan.FromSeconds(10)), "Test timed out");
                Thread.Sleep(TimeSpan.FromMilliseconds(500));
            }

            Thread.Sleep(TimeSpan.FromSeconds(1));
            Assert.Null(received);
        }
        public void when_creating_processor_then_receives_from_specified_subscription()
        {
            this.sut.Initialize();

            var waiter = new ManualResetEventSlim();
            var handler = new Mock<IEventHandler<AnEvent>>();
            var serializer = new JsonTextSerializer();
            var ev = new AnEvent();
            handler.Setup(x => x.Handle(It.IsAny<AnEvent>()))
                .Callback(() => waiter.Set());

            var processor = this.sut.CreateEventProcessor("log", handler.Object, serializer);

            processor.Start();

            var sender = new TopicSender(this.settings, this.settings.Topics.First(t => t.Path.StartsWith("conference/events")).Path);
            var bus = new EventBus(sender, new StandardMetadataProvider(), serializer);
            bus.Publish(ev);

            waiter.Wait(5000);

            handler.Verify(x => x.Handle(It.Is<AnEvent>(e => e.SourceId == ev.SourceId)));
        }