From 16710627155525e37ad88f90e2766843e5957cf1 Mon Sep 17 00:00:00 2001 From: ericuss Date: Tue, 3 Sep 2019 16:07:05 +0200 Subject: [PATCH] fix identity server --- .../Identity.API/IWebHostExtensions.cs | 79 +++++++++++++++++++ .../Identity/Identity.API/Identity.API.csproj | 13 ++- 2 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 src/Services/Identity/Identity.API/IWebHostExtensions.cs diff --git a/src/Services/Identity/Identity.API/IWebHostExtensions.cs b/src/Services/Identity/Identity.API/IWebHostExtensions.cs new file mode 100644 index 000000000..aff262b73 --- /dev/null +++ b/src/Services/Identity/Identity.API/IWebHostExtensions.cs @@ -0,0 +1,79 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Polly; +using System; +using System.Data.SqlClient; + +namespace Microsoft.AspNetCore.Hosting +{ + public static class IWebHostExtensions + { + public static bool IsInKubernetes(this IWebHost webHost) + { + var cfg = webHost.Services.GetService(); + var orchestratorType = cfg.GetValue("OrchestratorType"); + return orchestratorType?.ToUpper() == "K8S"; + } + + public static IWebHost MigrateDbContext(this IWebHost webHost, Action seeder) where TContext : DbContext + { + var underK8s = webHost.IsInKubernetes(); + + using (var scope = webHost.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 retries = 10; + var retry = Policy.Handle() + .WaitAndRetry( + retryCount: retries, + sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), + onRetry: (exception, timeSpan, retry, ctx) => + { + logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", nameof(TContext), exception.GetType().Name, exception.Message, retry, retries); + }); + + //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 webHost; + } + + private static void InvokeSeeder(Action seeder, TContext context, IServiceProvider services) + where TContext : DbContext + { + context.Database.Migrate(); + seeder(context, services); + } + } +} diff --git a/src/Services/Identity/Identity.API/Identity.API.csproj b/src/Services/Identity/Identity.API/Identity.API.csproj index ed9900f5c..068cc8a14 100644 --- a/src/Services/Identity/Identity.API/Identity.API.csproj +++ b/src/Services/Identity/Identity.API/Identity.API.csproj @@ -19,6 +19,8 @@ + + @@ -27,13 +29,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -41,8 +44,8 @@ - - + +