اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
دو دقیقه
در حین کار با بانکهای اطلاعاتی، ممکن است Timeout رخ دهد، یا اتصال برای لحظهای قطع شود و یا خطای قفل بودن جدولی مشاهده شود و امثال اینها. در این حالات، اعمال نتیجهی عملیات Migration با شکست مواجه خواهد شد. بنابراین اضافه کردن امکان سعی مجدد عملیات شکست خورده به آن، ضروری است.
پشتیبانی توکار EF Core از سعی مجدد یک عملیات شکست خورده
EF Core بدون نیاز به کتابخانه و یا راه حل ثالثی میتواند یک عملیات شکست خورده را مجددا اجرا کند. برای اینکار تنها کافی است تنظیمات زیر را به پروایدر مورد استفاده اضافه کنید؛ برای مثال در مورد SQL Server به صورت زیر است:
با تنظیم پارامترهای متد EnableRetryOnFailure در اینجا، یک عملیات شکست خورده، حداکثر 10 بار با یک مکث 30 ثانیهای در بین آنها، تکرار میشود.
مشکل! EnableRetryOnFailure به عملیات Migration اعمال نمیشود!
بر اساس نظر تیم EF Core، تنظیمات تکرار یک عملیات شکست خورده، در زمان اعمال نتیجهی عملیات Migrations ندید گرفته میشوند. بنابراین اگر در ابتدای اجرای برنامه قصد اجرای متد ()context.Database.Migrate را دارید تا از اعمال آخرین Migrations موجود اطمینان حاصل کنید و در این بین Timeout ای رخ دهد، این عملیات مجددا تکرار نخواهد شد و این مساله کار کردن با نگارشهای جدید یک برنامه را غیرممکن میکند؛ چون برنامهی جدید، بر اساس ساختار جدید بانک اطلاعاتی طراحی شده قرار است کار کند و به روز رسانی آن با شکست مواجه شدهاست.
اضافه کردن سعی مجدد در اجرای یک عملیات Migration شکست خورده با استفاده از Polly
در مورد کتابخانهی Polly پیشتر در مطلب «پیاده سازی مکانیسم سعی مجدد (Retry)» بحث شدهاست. در اینجا از امکانات این کتابخانه برای سعی مجدد در اجرای عملیات شکست خورده استفاده میکنیم:
- هدف از این متد الحاقی فراهم آوردن روشی برای اجرای به روز رسانی ساختار بانک اطلاعاتی، در زمان آغاز برنامهاست. به همین جهت به صورت افزونهای برای IHost تعریف شدهاست.
- همچنین چون DbContext با طول عمر Scoped تعریف میشود، نیاز است در اینجا و خارج از طول عمر یک درخواست، این Scope را به صورت دستی ایجاد و Dispose کرد.
- در این متد با استفاده از امکانات کتابخانهی Polly، در صورتیکه هر گونه خطایی رخ دهد، عملیات Migration سه بار با فواصل زمانی 5، 10 و 15 ثانیه، تکرار خواهد شد.
روش اعمال آن نیز به متد Main برنامه به صورت زیر است:
پشتیبانی توکار EF Core از سعی مجدد یک عملیات شکست خورده
EF Core بدون نیاز به کتابخانه و یا راه حل ثالثی میتواند یک عملیات شکست خورده را مجددا اجرا کند. برای اینکار تنها کافی است تنظیمات زیر را به پروایدر مورد استفاده اضافه کنید؛ برای مثال در مورد SQL Server به صورت زیر است:
public class Startup { // Other code ... public IServiceProvider ConfigureServices(IServiceCollection services) { // ... services.AddDbContext<CatalogContext>(options => { options.UseSqlServer(Configuration["ConnectionString"], sqlServerOptionsAction: sqlOptions => { sqlOptions.EnableRetryOnFailure( maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); }); }); } //... }
مشکل! EnableRetryOnFailure به عملیات Migration اعمال نمیشود!
بر اساس نظر تیم EF Core، تنظیمات تکرار یک عملیات شکست خورده، در زمان اعمال نتیجهی عملیات Migrations ندید گرفته میشوند. بنابراین اگر در ابتدای اجرای برنامه قصد اجرای متد ()context.Database.Migrate را دارید تا از اعمال آخرین Migrations موجود اطمینان حاصل کنید و در این بین Timeout ای رخ دهد، این عملیات مجددا تکرار نخواهد شد و این مساله کار کردن با نگارشهای جدید یک برنامه را غیرممکن میکند؛ چون برنامهی جدید، بر اساس ساختار جدید بانک اطلاعاتی طراحی شده قرار است کار کند و به روز رسانی آن با شکست مواجه شدهاست.
اضافه کردن سعی مجدد در اجرای یک عملیات Migration شکست خورده با استفاده از Polly
در مورد کتابخانهی Polly پیشتر در مطلب «پیاده سازی مکانیسم سعی مجدد (Retry)» بحث شدهاست. در اینجا از امکانات این کتابخانه برای سعی مجدد در اجرای عملیات شکست خورده استفاده میکنیم:
public static IHost MigrateDbContext<TContext>(this IHost host) where TContext : DbContext { using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; var logger = services.GetRequiredService<ILogger<TContext>>(); var context = services.GetService<TContext>(); logger.LogInformation($"Migrating the DB associated with the context {typeof(TContext).Name}"); var retry = Policy.Handle<Exception>().WaitAndRetry(new[] { TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15), }); retry.Execute(() => { context.Database.Migrate(); }); logger.LogInformation($"Migrated the DB associated with the context {typeof(TContext).Name}"); } return host; }
- همچنین چون DbContext با طول عمر Scoped تعریف میشود، نیاز است در اینجا و خارج از طول عمر یک درخواست، این Scope را به صورت دستی ایجاد و Dispose کرد.
- در این متد با استفاده از امکانات کتابخانهی Polly، در صورتیکه هر گونه خطایی رخ دهد، عملیات Migration سه بار با فواصل زمانی 5، 10 و 15 ثانیه، تکرار خواهد شد.
روش اعمال آن نیز به متد Main برنامه به صورت زیر است:
public static void Main(string[] args) { CreateHostBuilder(args) .Build() .MigrateDbContext<AppDbContext>() .Run(); }