From 49aac0ce77563c2832b1741d56095baafbb8b94c Mon Sep 17 00:00:00 2001 From: Sumit Ghosh <13281246+sughosneo@users.noreply.github.com> Date: Mon, 24 Aug 2020 15:11:18 +0530 Subject: [PATCH] Introducted Retry logic in Marketing.API with polly policy. --- .../Controllers/CampaignsController.cs | 2 +- .../Extensions/WebHostExtensions.cs | 75 +++++++++++++++++++ .../Marketing.API/Marketing.API.csproj | 3 + .../Marketing/Marketing.API/Startup.cs | 6 +- 4 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/Services/Marketing/Marketing.API/Extensions/WebHostExtensions.cs diff --git a/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs b/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs index 67ac1bca5..f8c395182 100644 --- a/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs +++ b/src/Services/Marketing/Marketing.API/Controllers/CampaignsController.cs @@ -13,7 +13,7 @@ namespace Microsoft.eShopOnContainers.Services.Marketing.API.Controllers using EntityFrameworkCore; using Dto; using AspNetCore.Authorization; - using Extensions.Options; + using Microsoft.Extensions.Options; using Microsoft.eShopOnContainers.Services.Marketing.API.ViewModel; using Microsoft.AspNetCore.Http; using System.Net; diff --git a/src/Services/Marketing/Marketing.API/Extensions/WebHostExtensions.cs b/src/Services/Marketing/Marketing.API/Extensions/WebHostExtensions.cs new file mode 100644 index 000000000..7090b07d1 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Extensions/WebHostExtensions.cs @@ -0,0 +1,75 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Polly; +using System.Data.SqlClient; +using Microsoft.AspNetCore.Hosting; + +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Extensions +{ + public static class WebHostExtensions + { + public static bool IsInKubernetes(this IWebHost host) + { + var cfg = host.Services.GetService(); + var orchestratorType = cfg.GetValue("OrchestratorType"); + return orchestratorType?.ToUpper() == "K8S"; + } + + public static IWebHost MigrateDbContext(this IWebHost host, Action seeder) where TContext : DbContext + { + var underK8s = host.IsInKubernetes(); + + using (var scope = host.Services.CreateScope()) + { + var services = scope.ServiceProvider; + + var logger = services.GetRequiredService>(); + + var context = services.GetService(); + + try + { + logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name); + + if (underK8s) + { + InvokeSeeder(seeder, context, services); + } + else + { + var retry = Policy.Handle() + .WaitAndRetry(10, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + + //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 + // Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service) + retry.Execute(() => InvokeSeeder(seeder, context, services)); + } + + logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name); + } + catch (Exception ex) + { + logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name); + if (underK8s) + { + throw; // Rethrow under k8s because we rely on k8s to re-run the pod + } + } + } + + return host; + } + + private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) + where TContext : DbContext + { + context.Database.Migrate(); + seeder(context, services); + } + } +} diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index bc3116fc3..0cf1566a4 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -38,11 +38,14 @@ + + + diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index a7386a532..de22de6c5 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -11,9 +11,9 @@ using BuildingBlocks.EventBusRabbitMQ; using BuildingBlocks.EventBusServiceBus; using EntityFrameworkCore; - using Extensions.Configuration; - using Extensions.DependencyInjection; - using Extensions.Logging; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; using HealthChecks.UI.Client; using Infrastructure; using Infrastructure.Filters;