22using System . Data . SqlClient ;
33using Microsoft . AspNetCore . Hosting ;
44using Microsoft . EntityFrameworkCore ;
5- using Microsoft . Extensions . Configuration ;
65using Microsoft . Extensions . DependencyInjection ;
76using Microsoft . Extensions . Logging ;
87using Polly ;
@@ -11,46 +10,77 @@ namespace Extensions
1110{
1211 public static class IWebHostExtensions
1312 {
14- public static bool IsInKubernetes ( this IWebHost webHost )
13+ public static IWebHost MigrateDbContext < TContext > ( this IWebHost webHost ) where TContext : DbContext
1514 {
16- var cfg = webHost . Services . GetService < IConfiguration > ( ) ;
17- return CheckIfK8s ( cfg ) ;
15+ using var scope = webHost . Services . CreateScope ( ) ;
16+
17+ TryMigrate < TContext > ( scope ) ;
18+
19+ return webHost ;
1820 }
1921
20- private static bool CheckIfK8s ( IConfiguration cfg )
22+ public static Microsoft . Extensions . Hosting . IHost MigrateDbContext < TContext > ( this Microsoft . Extensions . Hosting . IHost host ) where TContext : DbContext
2123 {
22- var orchestratorType = cfg . GetValue < string > ( "OrchestratorType" ) ;
23- return orchestratorType ? . ToUpper ( ) == "K8S" ;
24+ using var scope = host . Services . CreateScope ( ) ;
25+
26+ TryMigrate < TContext > ( scope ) ;
27+
28+ return host ;
2429 }
2530
26- public static IWebHost MigrateDbContext < TContext > ( this IWebHost webHost , Action < TContext , IServiceProvider > seeder ) where TContext : DbContext
31+ public static IWebHost MigrateDbContext < TContext > ( this IWebHost webHost , Action < TContext , IServiceProvider > seeder = default ) where TContext : DbContext
2732 {
28- var underK8s = webHost . IsInKubernetes ( ) ;
29-
3033 using var scope = webHost . Services . CreateScope ( ) ;
3134
32- TryMigrateAndSeed ( scope , underK8s , seeder ) ;
35+ TryMigrateAndSeed ( scope , seeder ) ;
3336
3437 return webHost ;
3538 }
3639
37- public static bool IsInKubernetes ( this Microsoft . Extensions . Hosting . IHost host )
40+ public static Microsoft . Extensions . Hosting . IHost MigrateDbContext < TContext > ( this Microsoft . Extensions . Hosting . IHost host , Action < TContext , IServiceProvider > seeder = default ) where TContext : DbContext
3841 {
39- var cfg = host . Services . GetService < IConfiguration > ( ) ;
40- return CheckIfK8s ( cfg ) ;
42+ using var scope = host . Services . CreateScope ( ) ;
43+
44+ TryMigrateAndSeed ( scope , seeder ) ;
45+
46+ return host ;
4147 }
4248
43- public static Microsoft . Extensions . Hosting . IHost MigrateDbContext < TContext > ( this Microsoft . Extensions . Hosting . IHost webHost , Action < TContext , IServiceProvider > seeder ) where TContext : DbContext
49+ private static void TryMigrateAndSeed < TContext > ( IServiceScope scope , Action < TContext , IServiceProvider > seeder ) where TContext : DbContext
4450 {
45- var underK8s = webHost . IsInKubernetes ( ) ;
51+ var services = scope . ServiceProvider ;
4652
47- using var scope = webHost . Services . CreateScope ( ) ;
48- TryMigrateAndSeed ( scope , underK8s , seeder ) ;
53+ var logger = services . GetRequiredService < ILogger < TContext > > ( ) ;
4954
50- return webHost ;
55+ var context = services . GetService < TContext > ( ) ;
56+
57+ try
58+ {
59+ logger . LogInformation ( "Migrating database associated with context {DbContextName}" , typeof ( TContext ) . Name ) ;
60+
61+
62+ var retry = Policy . Handle < SqlException > ( )
63+ . WaitAndRetry ( new TimeSpan [ ]
64+ {
65+ TimeSpan . FromSeconds ( 3 ) ,
66+ TimeSpan . FromSeconds ( 5 ) ,
67+ TimeSpan . FromSeconds ( 8 ) ,
68+ } ) ;
69+
70+ //if the sql server container is not created on run docker compose this
71+ //migration can't fail for network related exception. The retry options for DbContext only
72+ //apply to transient exceptions
73+ retry . Execute ( ( ) => InvokeSeeder ( seeder , context , services ) ) ;
74+
75+ logger . LogInformation ( "Migrated database associated with context {DbContextName}" , typeof ( TContext ) . Name ) ;
76+ }
77+ catch ( Exception ex )
78+ {
79+ logger . LogError ( ex , "An error occurred while migrating the database used on context {DbContextName}" , typeof ( TContext ) . Name ) ;
80+ }
5181 }
5282
53- private static void TryMigrateAndSeed < TContext > ( IServiceScope scope , bool underK8s , Action < TContext , IServiceProvider > seeder ) where TContext : DbContext
83+ private static void TryMigrate < TContext > ( IServiceScope scope ) where TContext : DbContext
5484 {
5585 var services = scope . ServiceProvider ;
5686
@@ -62,36 +92,25 @@ private static void TryMigrateAndSeed<TContext>(IServiceScope scope, bool underK
6292 {
6393 logger . LogInformation ( "Migrating database associated with context {DbContextName}" , typeof ( TContext ) . Name ) ;
6494
65- if ( underK8s )
66- {
67- InvokeSeeder ( seeder , context , services ) ;
68- }
69- else
70- {
71- var retry = Policy . Handle < SqlException > ( )
72- . WaitAndRetry ( new TimeSpan [ ]
73- {
95+
96+ var retry = Policy . Handle < SqlException > ( )
97+ . WaitAndRetry ( new TimeSpan [ ]
98+ {
7499 TimeSpan . FromSeconds ( 3 ) ,
75100 TimeSpan . FromSeconds ( 5 ) ,
76101 TimeSpan . FromSeconds ( 8 ) ,
77- } ) ;
102+ } ) ;
78103
79- //if the sql server container is not created on run docker compose this
80- //migration can't fail for network related exception. The retry options for DbContext only
81- //apply to transient exceptions
82- // Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service)
83- retry . Execute ( ( ) => InvokeSeeder ( seeder , context , services ) ) ;
84- }
104+ //if the sql server container is not created on run docker compose this
105+ //migration can't fail for network related exception. The retry options for DbContext only
106+ //apply to transient exceptions
107+ retry . Execute ( ( ) => context . Database . Migrate ( ) ) ;
85108
86109 logger . LogInformation ( "Migrated database associated with context {DbContextName}" , typeof ( TContext ) . Name ) ;
87110 }
88111 catch ( Exception ex )
89112 {
90113 logger . LogError ( ex , "An error occurred while migrating the database used on context {DbContextName}" , typeof ( TContext ) . Name ) ;
91- if ( underK8s )
92- {
93- throw ; // Rethrow under k8s because we rely on k8s to re-run the pod
94- }
95114 }
96115 }
97116
0 commit comments