diff --git a/.env b/.env index c8fcdfcf2..28a94504c 100644 --- a/.env +++ b/.env @@ -5,7 +5,7 @@ # The IP below should be swapped to your real IP or DNS name, like 192.168.88.248, etc. if testing from remote browsers or mobile devices ESHOP_EXTERNAL_DNS_NAME_OR_IP=localhost -ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=10.121.122.92 +ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=10.121.122.162 #ESHOP_AZURE_REDIS_BASKET_DB= #ESHOP_AZURE_STORAGE_CATALOG_URL= diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 5a15ab408..7ba049015 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -8,7 +8,7 @@ version: '3' # # IMPORTANT: Note that this compose file uses ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP instead of ESHOP_EXTERNAL_DNS_NAME_OR_IP -# Set ASPNETCORE_ENVIRONMENT=Development, instead Production, if you want to show up errors while testing. +# Set ASPNETCORE_ENVIRONMENT= Development or Production, depending if you want to show up errors while testing. # # You need to start it with the following CLI command: # docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d @@ -17,7 +17,7 @@ services: basket.api: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket.data} - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. @@ -35,7 +35,7 @@ services: catalog.api: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5101/api/v1/catalog/items/[0]/pic/} #Local: You need to open your local dev-machine firewall at range 5100-5110. @@ -54,7 +54,7 @@ services: identity.api: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104 - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback #localhost do not work for UWP login, so we have to use "external" IP always @@ -72,7 +72,7 @@ services: ordering.api: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110. @@ -92,7 +92,7 @@ services: marketing.api: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} @@ -116,7 +116,7 @@ services: webspa: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - CatalogUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 - OrderingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5102 @@ -126,7 +126,7 @@ services: - LocationsUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5109 - CatalogUrlHC=http://catalog.api/hc - OrderingUrlHC=http://ordering.api/hc - - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. + - IdentityUrlHC=http://identity.api/hc - BasketUrlHC=http://basket.api/hc - MarketingUrlHC=http://marketing.api/hc - PaymentUrlHC=http://payment.api/hc @@ -138,17 +138,17 @@ services: webmvc: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - CatalogUrl=http://catalog.api - OrderingUrl=http://ordering.api - BasketUrl=http://basket.api - LocationsUrl=http://locations.api - - IdentityUrl=http://10.0.75.1:5105 - - MarketingUrl=http://marketing.api #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. #Remote: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. + - IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. #Remote: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser. + - MarketingUrl=http://marketing.api - CatalogUrlHC=http://catalog.api/hc - OrderingUrlHC=http://ordering.api/hc - - IdentityUrlHC=http://identity.api/hc #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser. + - IdentityUrlHC=http://identity.api/hc - BasketUrlHC=http://basket.api/hc - MarketingUrlHC=http://marketing.api/hc - PaymentUrlHC=http://payment.api/hc @@ -161,7 +161,7 @@ services: webstatus: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - CatalogUrl=http://catalog.api/hc - OrderingUrl=http://ordering.api/hc @@ -179,7 +179,7 @@ services: payment.api: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} @@ -192,7 +192,7 @@ services: locations.api: environment: - - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} - Database=LocationsDb diff --git a/docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook)-v1.pdf b/docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook)-v1.pdf new file mode 100644 index 000000000..7f5d6885d Binary files /dev/null and b/docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook)-v1.pdf differ diff --git a/docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook).pdf b/docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook).pdf index 7f5d6885d..9c79a8bea 100644 Binary files a/docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook).pdf and b/docs/NET-Microservices-Architecture-for-Containerized-NET-Applications-(Microsoft-eBook).pdf differ diff --git a/img/loadtests/k8ssettings.PNG b/img/loadtests/k8ssettings.PNG new file mode 100644 index 000000000..6bd6cb058 Binary files /dev/null and b/img/loadtests/k8ssettings.PNG differ diff --git a/img/loadtests/loadtestproj_dir.PNG b/img/loadtests/loadtestproj_dir.PNG new file mode 100644 index 000000000..d880e9ecc Binary files /dev/null and b/img/loadtests/loadtestproj_dir.PNG differ diff --git a/img/loadtests/runloadtest.PNG b/img/loadtests/runloadtest.PNG new file mode 100644 index 000000000..8c2cbdec2 Binary files /dev/null and b/img/loadtests/runloadtest.PNG differ diff --git a/img/loadtests/sfmanifestsettings.PNG b/img/loadtests/sfmanifestsettings.PNG new file mode 100644 index 000000000..b360fef63 Binary files /dev/null and b/img/loadtests/sfmanifestsettings.PNG differ diff --git a/src/BuildingBlocks/EventBus/EventBus/Abstractions/IEventBus.cs b/src/BuildingBlocks/EventBus/EventBus/Abstractions/IEventBus.cs index 21436d3cd..dde05e1e3 100644 --- a/src/BuildingBlocks/EventBus/EventBus/Abstractions/IEventBus.cs +++ b/src/BuildingBlocks/EventBus/EventBus/Abstractions/IEventBus.cs @@ -5,9 +5,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions { public interface IEventBus { + void Publish(IntegrationEvent @event); + void Subscribe() where T : IntegrationEvent where TH : IIntegrationEventHandler; + void SubscribeDynamic(string eventName) where TH : IDynamicIntegrationEventHandler; @@ -17,7 +20,5 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions void Unsubscribe() where TH : IIntegrationEventHandler where T : IntegrationEvent; - - void Publish(IntegrationEvent @event); } } diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/CommandBusRabbitMQ.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/CommandBusRabbitMQ.cs deleted file mode 100644 index 27e67d9ca..000000000 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/CommandBusRabbitMQ.cs +++ /dev/null @@ -1,145 +0,0 @@ -//using Microsoft.eShopOnContainers.BuildingBlocks.CommandBus; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Polly; -using Polly.Retry; -using RabbitMQ.Client; -using RabbitMQ.Client.Events; -using RabbitMQ.Client.Exceptions; -using System; -using System.Collections.Generic; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; - -/* -namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ -{ - public class CommandBusRabbitMQ : ICommandBus, IDisposable - { - const string BROKER_NAME = "eshop_command_bus"; - - private readonly IRabbitMQPersistentConnection _persistentConnection; - private readonly ILogger _logger; - - private IModel _consumerChannel; - private string _queueName; - - private readonly Dictionary _handlers; - private readonly Dictionary _typeMappings; - - public CommandBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, - ILogger logger) - { - _logger = logger; - _persistentConnection = persistentConnection; - _handlers = new Dictionary(); - _typeMappings = new Dictionary(); - } - - public void Send(string name, T data) - { - Send(new IntegrationCommand(name, data)); - } - - public void Handle(string name, IIntegrationCommandHandler handler) - { - _handlers.Add(name, handler); - _typeMappings.Add(name, typeof(TC)); - } - - public void Handle(string name, IIntegrationCommandHandler handler) - { - _handlers.Add(name, handler); - } - public void Handle(TI handler) where TI : IIntegrationCommandHandler - { - var name = typeof(TI).Name; - _handlers.Add(name, handler); - _typeMappings.Add(name, typeof(TC)); - } - - private void Send(IntegrationCommand command) - { - if (!_persistentConnection.IsConnected) - { - _persistentConnection.TryConnect(); - } - - var policy = RetryPolicy.Handle() - .Or() - .WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => - { - _logger.LogWarning(ex.ToString()); - }); - - using (var channel = _persistentConnection.CreateModel()) - { - var commandName = command.Name; - channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); - var message = JsonConvert.SerializeObject(command); - var body = Encoding.UTF8.GetBytes(message); - policy.Execute(() => - { - channel.BasicPublish(exchange: BROKER_NAME, - routingKey: commandName, - basicProperties: null, - body: body); - }); - } - } - - private IModel CreateConsumerChannel() - { - if (!_persistentConnection.IsConnected) - { - _persistentConnection.TryConnect(); - } - - var channel = _persistentConnection.CreateModel(); - - channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); - _queueName = channel.QueueDeclare().QueueName; - var consumer = new EventingBasicConsumer(channel); - consumer.Received += async (model, ea) => - { - var commandName = ea.RoutingKey; - var message = Encoding.UTF8.GetString(ea.Body); - await InvokeHandler(commandName, message); - }; - - channel.BasicConsume(queue: _queueName, - noAck: true, - consumer: consumer); - - channel.CallbackException += (sender, ea) => - { - _consumerChannel.Dispose(); - _consumerChannel = CreateConsumerChannel(); - }; - - return channel; - } - - private Task InvokeHandler(string commandName, string message) - { - if (_handlers.ContainsKey(commandName)) - { - - } - - } - - public void Dispose() - { - if (_consumerChannel != null) - { - _consumerChannel.Dispose(); - } - } - - - - } -} -*/ \ No newline at end of file diff --git a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs index 2416e1d55..f2129be69 100644 --- a/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs +++ b/src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.cs @@ -32,11 +32,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ private string _queueName; public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger logger, - ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, int retryCount = 5) + ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, string queueName = null, int retryCount = 5) { _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); + _queueName = queueName; _consumerChannel = CreateConsumerChannel(); _autofac = autofac; _retryCount = retryCount; @@ -147,7 +148,6 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ _subsManager.RemoveDynamicSubscription(eventName); } - public void Dispose() { if (_consumerChannel != null) @@ -170,7 +170,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); - _queueName = channel.QueueDeclare().QueueName; + channel.QueueDeclare(queue: _queueName, + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); + var consumer = new EventingBasicConsumer(channel); consumer.Received += async (model, ea) => @@ -196,8 +201,6 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ private async Task ProcessEvent(string eventName, string message) { - - if (_subsManager.HasSubscriptionsForEvent(eventName)) { using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) diff --git a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj index d9ddd56e9..db3926d0d 100644 --- a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj +++ b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj @@ -6,6 +6,7 @@ + diff --git a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs index ecaceeab0..858506e46 100644 --- a/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs +++ b/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHostExtensions.cs @@ -1,7 +1,10 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Polly; +using Polly.Retry; using System; +using System.Data.SqlClient; namespace Microsoft.AspNetCore.Hosting { @@ -21,10 +24,26 @@ namespace Microsoft.AspNetCore.Hosting { logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}"); - context.Database + var retry = Policy.Handle() + .WaitAndRetry(new TimeSpan[] + { + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(10), + TimeSpan.FromSeconds(15), + }); + + retry.Execute(() => + { + //if the sql server container is not created on run docker compose this + //migration can't fail for network related exception. The retry options for DbContext only + //apply to transient exceptions. + + context.Database .Migrate(); - seeder(context,services); + seeder(context, services); + }); + logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}"); } diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml index 79b0ff307..481c5c100 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/App.xaml @@ -34,148 +34,139 @@ Transparent Transparent - + + + - + + + + - + + + + - + + + + - + + + + - + + + + - + + + - + + + - + + + + + - + + + + + - + + + + + - + + + + - + + + + - + + + + - + + + + - + + + + - + + + + - + + + + - + + + + - + + + + - + + + + - + + + + diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/AddBasketButton.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/AddBasketButton.xaml index 034af4954..866cdbfb1 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/AddBasketButton.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Controls/AddBasketButton.xaml @@ -44,11 +44,10 @@ - + + + + - + + + + - + + + + diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CampaignView.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CampaignView.xaml index 7faf088a0..0ec8f0a6b 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CampaignView.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CampaignView.xaml @@ -90,11 +90,10 @@ VerticalOptions="Center" HorizontalOptions="Center"> - + + + + diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CatalogView.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CatalogView.xaml index d7d68d1f5..6f834d7c0 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CatalogView.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CatalogView.xaml @@ -114,11 +114,10 @@ VerticalOptions="Center" HorizontalOptions="Center"> - + + + + diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CheckoutView.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CheckoutView.xaml index 12fcaaabe..7b3b47077 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CheckoutView.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/CheckoutView.xaml @@ -231,11 +231,10 @@ VerticalOptions="Center" HorizontalOptions="Center"> - + + + + diff --git a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/FiltersView.xaml b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/FiltersView.xaml index 9a9d4f04a..b7ebe0c0a 100644 --- a/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/FiltersView.xaml +++ b/src/Mobile/eShopOnContainers/eShopOnContainers.Core/Views/FiltersView.xaml @@ -76,11 +76,10 @@ SelectedItem="{Binding Brand, Mode=TwoWay}" Style="{StaticResource FilterPickerStyle}"> - + + + + @@ -91,11 +90,10 @@ SelectedItem="{Binding Type, Mode=TwoWay}" Style="{StaticResource FilterPickerStyle}"> - + + + +