feat: добавил инвалидацию кэшей плагинов
Create and publish a Docker image / Publish image (push) Successful in 1m53s
Create and publish a Docker image / Publish image (push) Successful in 1m53s
This commit is contained in:
1 parent
01bab77900
commit
c590a8a6c7
5 files changed
+51
-4
No files matched your search
@@ -10,4 +10,8 @@ public interface IPlugin
|
|||||||
|
|
||||||
// Регистрация маршрутов (Minimal API) плагина после Build()
|
// Регистрация маршрутов (Minimal API) плагина после Build()
|
||||||
void MapEndpoints(IEndpointRouteBuilder endpoints);
|
void MapEndpoints(IEndpointRouteBuilder endpoints);
|
||||||
}
|
|
||||||
|
// Инвалидация или обновление внутренних кэшей плагина.
|
||||||
|
Task InvalidateCacheAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) =>
|
||||||
|
Task.CompletedTask;
|
||||||
|
}
|
||||||
@@ -89,6 +89,7 @@
|
|||||||
- загружает большой список сотрудников;
|
- загружает большой список сотрудников;
|
||||||
- группирует записи по ФИО;
|
- группирует записи по ФИО;
|
||||||
- сохраняет результат на диск;
|
- сохраняет результат на диск;
|
||||||
|
- после успешного обновления предлагает всем плагинам инвалидировать свои кэши;
|
||||||
- повторяет попытки при временных сбоях.
|
- повторяет попытки при временных сбоях.
|
||||||
|
|
||||||
Если сервис ещё не инициализирован, `GET /api/schedule/searchemployee` возвращает `503`.
|
Если сервис ещё не инициализирован, `GET /api/schedule/searchemployee` возвращает `503`.
|
||||||
@@ -131,7 +132,11 @@ Quartz job [UpdateJwtJob](/home/serega404/Рабочий стол/SfeduSchedule/
|
|||||||
На старте хост ищет все `*.plugin.dll` внутри `data/Plugins` и загружает найденные сборки как плагины. Плагин должен реализовывать интерфейс [IPlugin](/home/serega404/Рабочий стол/SfeduSchedule/ModeusSchedule.Abstractions/IPlugin.cs), чтобы:
|
На старте хост ищет все `*.plugin.dll` внутри `data/Plugins` и загружает найденные сборки как плагины. Плагин должен реализовывать интерфейс [IPlugin](/home/serega404/Рабочий стол/SfeduSchedule/ModeusSchedule.Abstractions/IPlugin.cs), чтобы:
|
||||||
|
|
||||||
- зарегистрировать свои сервисы в DI через `ConfigureServices`;
|
- зарегистрировать свои сервисы в DI через `ConfigureServices`;
|
||||||
- добавить minimal API маршруты через `MapEndpoints`.
|
- добавить minimal API маршруты через `MapEndpoints`;
|
||||||
|
- опционально обновить или очистить свои кэши через `InvalidateCacheAsync`.
|
||||||
|
|
||||||
|
`InvalidateCacheAsync` имеет default-реализацию, поэтому плагины, собранные до добавления этого метода,
|
||||||
|
продолжают загружаться. Ошибка инвалидации одного плагина логируется и не мешает вызвать остальные.
|
||||||
|
|
||||||
MVC-контроллеры из плагинов тоже подключаются автоматически через `ApplicationPart`.
|
MVC-контроллеры из плагинов тоже подключаются автоматически через `ApplicationPart`.
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ namespace SfeduSchedule.Jobs;
|
|||||||
public class UpdateEmployeesJob(
|
public class UpdateEmployeesJob(
|
||||||
ILogger<UpdateEmployeesJob> logger,
|
ILogger<UpdateEmployeesJob> logger,
|
||||||
ModeusEmployeeService employeeService,
|
ModeusEmployeeService employeeService,
|
||||||
ModeusService modeusService) : IJob
|
ModeusService modeusService,
|
||||||
|
PluginCacheInvalidator pluginCacheInvalidator) : IJob
|
||||||
{
|
{
|
||||||
private const int MaxAttempts = 5; // Максимальное число попыток
|
private const int MaxAttempts = 5; // Максимальное число попыток
|
||||||
private const int DelaySeconds = 50; // Задержка между попытками в секундах
|
private const int DelaySeconds = 50; // Задержка между попытками в секундах
|
||||||
@@ -47,6 +48,7 @@ public class UpdateEmployeesJob(
|
|||||||
|
|
||||||
await employeeService.SetEmployees(employees);
|
await employeeService.SetEmployees(employees);
|
||||||
logger.LogInformationHere($"Получено {employees.Count} сотрудников из Modeus.");
|
logger.LogInformationHere($"Получено {employees.Count} сотрудников из Modeus.");
|
||||||
|
await pluginCacheInvalidator.InvalidateAsync(jobContext.CancellationToken);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException ex)
|
catch (OperationCanceledException ex)
|
||||||
@@ -75,4 +77,4 @@ public class UpdateEmployeesJob(
|
|||||||
await Task.Delay(TimeSpan.FromSeconds(DelaySeconds), jobContext.CancellationToken);
|
await Task.Delay(TimeSpan.FromSeconds(DelaySeconds), jobContext.CancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.HttpOverrides;
|
|||||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||||
using Microsoft.Identity.Web;
|
using Microsoft.Identity.Web;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using ModeusSchedule.Abstractions;
|
||||||
using Prometheus;
|
using Prometheus;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
using Quartz.Listener;
|
using Quartz.Listener;
|
||||||
@@ -133,11 +134,14 @@ foreach (var p in loadedPlugins)
|
|||||||
|
|
||||||
// DI из плагина
|
// DI из плагина
|
||||||
p.Instance.ConfigureServices(builder.Services);
|
p.Instance.ConfigureServices(builder.Services);
|
||||||
|
builder.Services.AddSingleton<IPlugin>(p.Instance);
|
||||||
|
|
||||||
// Подключаем контроллеры плагина
|
// Подключаем контроллеры плагина
|
||||||
mvcBuilder.PartManager.ApplicationParts.Add(new AssemblyPart(p.Assembly));
|
mvcBuilder.PartManager.ApplicationParts.Add(new AssemblyPart(p.Assembly));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<PluginCacheInvalidator>();
|
||||||
|
|
||||||
var updateJwtJob = new JobKey("UpdateJWTJob");
|
var updateJwtJob = new JobKey("UpdateJWTJob");
|
||||||
|
|
||||||
builder.Services.AddQuartz(q =>
|
builder.Services.AddQuartz(q =>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using ModeusSchedule.Abstractions;
|
||||||
|
|
||||||
|
namespace SfeduSchedule.Services;
|
||||||
|
|
||||||
|
public sealed class PluginCacheInvalidator(
|
||||||
|
IEnumerable<IPlugin> plugins,
|
||||||
|
IServiceScopeFactory scopeFactory,
|
||||||
|
ILogger<PluginCacheInvalidator> logger)
|
||||||
|
{
|
||||||
|
public async Task InvalidateAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
foreach (var plugin in plugins)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var scope = scopeFactory.CreateAsyncScope();
|
||||||
|
await plugin.InvalidateCacheAsync(scope.ServiceProvider, cancellationToken);
|
||||||
|
logger.LogInformation("Кэш плагина {PluginName} инвалидирован", plugin.Name);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, "Не удалось инвалидировать кэш плагина {PluginName}", plugin.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user