共用方式為


背景服務和啟動工作

建置 Orleans 應用程式時,您通常需要在應用程式啟動時執行背景作業或初始化元件。

啟動工作可用來在存放區啟動時,於接收要求開始之前或之後,執行初始化工作。 常見的使用案例包括:

  • 初始化粒紋狀態或預先載入數據
  • 設定外部服務連線
  • 執行資料庫移轉
  • 驗證組態
  • 快取預熱

建議的方法是使用 .NET BackgroundService 或 IHostedService。 如需詳細資訊,請參閱 ASP.NET Core 檔中具有託管服務的 背景工作。

以下是每隔 5 秒 Ping 一次粒紋的範例:

public class GrainPingService : BackgroundService
{
    private readonly IGrainFactory _grainFactory;
    private readonly ILogger<GrainPingService> _logger;

    public GrainPingService(
        IGrainFactory grainFactory,
        ILogger<GrainPingService> logger)
    {
        _grainFactory = grainFactory;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                try
                {
                    _logger.LogInformation("Pinging grain...");
                    var grain = _grainFactory.GetGrain<IMyGrain>("ping-target");
                    await grain.Ping();
                }
                catch (Exception ex) when (ex is not OperationCanceledException)
                {
                    // Log the error but continue running
                    _logger.LogError(ex, "Failed to ping grain. Will retry in 5 seconds.");
                }

                await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
            }
        }
        catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
        {
            // Ignore cancellation during shutdown.
        }
        finally
        {
            _logger.LogInformation("Grain ping service is shutting down.");
        }
    }
}

註冊順序相當重要,因為新增至主機產生器的服務會依註冊的順序逐一啟動。 您可以註冊背景服務,如下所示:

var builder = WebApplication.CreateBuilder(args);

// Configure Orleans first
builder.UseOrleans(siloBuilder => 
{
    // Orleans configuration...
});

// Register the background service after calling 'UseOrleans' to make it start once Orleans has started.
builder.Services.AddHostedService<GrainPingService>();

var app = builder.Build();

背景服務會在應用程式啟動時自動啟動,並在應用程式停止時正常關閉。

使用 IHostedService

針對不需要連續背景作業的較簡單案例,您可以直接實作 IHostedService

public class GrainInitializerService : IHostedService
{
    private readonly IGrainFactory _grainFactory;
    private readonly ILogger<GrainInitializerService> _logger;

    public GrainInitializerService(
        IGrainFactory grainFactory,
        ILogger<GrainInitializerService> logger)
    {
        _grainFactory = grainFactory;
        _logger = logger;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Initializing grains...");
        var grain = _grainFactory.GetGrain<IMyGrain>("initializer");
        await grain.Initialize();
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

請以相同的方式註冊:

builder.Services.AddHostedService<GrainInitializerService>();

Orleans' 啟動工作

注意

雖然仍支持啟動工作,但建議改用 BackgroundServiceIHostedService,因為它們是執行背景工作的常見 .NET 裝載機制。

警告

從啟動工作擲出的任何異常都會在silo日誌中報告,並將導致silo停止。 這個快速失敗策略有助於在測試期間偵測設定和引導程序問題,而不是在稍後造成非預期的問題,但這也表示,啟動工作中的暫時性失敗可能會導致主機暫時無法使用。

如果您需要使用內建啟動工作系統,您可以設定它們,如下所示:

註冊代表

可以將委派使用適當的 AddStartupTask 擴充方法在 ISiloBuilder上註冊為啟動程序。

siloBuilder.AddStartupTask(
    async (IServiceProvider services, CancellationToken cancellation) =>
    {
        var grainFactory = services.GetRequiredService<IGrainFactory>();
        var grain = grainFactory.GetGrain<IMyGrain>("startup-task-grain");
        await grain.Initialize();
    });

註冊 IStartupTask 實作

您可以在 ISiloBuilder上使用 AddStartupTask 擴充方法,實作 IStartupTask 介面並註冊為啟動工作。

public class CallGrainStartupTask : IStartupTask
{
    private readonly IGrainFactory _grainFactory;

    public CallGrainStartupTask(IGrainFactory grainFactory) =>
        _grainFactory = grainFactory;

    public async Task Execute(CancellationToken cancellationToken)
    {
        var grain = _grainFactory.GetGrain<IMyGrain>("startup-task-grain");
        await grain.Initialize();
    }
}

註冊啟動任務,如下所示:

siloBuilder.AddStartupTask<CallGrainStartupTask>();