使用 Service Fabric 託管

可以使用 Microsoft.ServiceFabric.ServicesMicrosoft.Orleans.Server NuGet 套件,在 Azure Service Fabric 上託管 Orleans。 定址接收器應該託管為未分割的無狀態服務,因為 Orleans 會管理精細度本身的分佈。 其他託管選項 (例如分割和具狀態方式) 會比較複雜,如果開發人員端未進行額外的自訂,則不會帶來任何益處。 建議您以未分割和無狀態的方式託管 Orleans。

作為定址接收器的 Service Fabric 無狀態服務

無論您是建立新的 Service Fabric 應用程式或將 Orleans 新增至現有的 Service Fabric 應用程式,您都需要專案中的 Microsoft.ServiceFabric.ServicesMicrosoft.Orleans.Server 套件參考。 無狀態服務專案需要在 ICommunicationListenerStatelessService 子類別上實作。

定址接收器生命週期遵循典型的通訊接聽程式生命週期:

由於 Orleans 定址接收器能夠在 IHost 的範圍運作,所以 ICommunicationListener 的實作是在 IHost 周圍的包裝函式。 會在 OpenAsync 方法中初始化 IHost,並在 CloseAsync 方法中正常終止:

ICommunicationListener IHost 互動
OpenAsync 系統會建立 IHost 執行個體,並呼叫 StartAsync
CloseAsync 等候在主機執行個體上呼叫 StopAsync
Abort 使用 GetAwaiter().GetResult() 強制評估對 StopAsync 的呼叫。

叢隻支援

您可從各種套件取得官方叢集支援,包括:

也有數個協力廠商套件可供其他服務使用,例如 CosmosDB、Kubernetes、Redis 和 Aerospike。 如需詳細資訊,請參閱在 Orleans 中的叢集管理

範例專案

如下列範例所示,在無狀態服務專案中,實作 ICommunicationListener 介面:

using Microsoft.Extensions.Hosting;
using Microsoft.ServiceFabric.Services.Communication.Runtime;

namespace ServiceFabric.HostingExample;

internal sealed class HostedServiceCommunicationListener : ICommunicationListener
{
    private IHost? _host;
    private readonly Func<Task<IHost>> _createHost;

    public HostedServiceCommunicationListener(Func<Task<IHost>> createHost) =>
        _createHost = createHost ?? throw new ArgumentNullException(nameof(createHost));

    /// <inheritdoc />
    public async Task<string?> OpenAsync(CancellationToken cancellationToken)
    {
        try
        {
            _host = await _createHost.Invoke();
            await _host.StartAsync(cancellationToken);
        }
        catch
        {
            Abort();
            throw;
        }

        // This service does not expose any endpoints to Service Fabric for discovery by others.
        return null;
    }

    /// <inheritdoc />
    public async Task CloseAsync(CancellationToken cancellationToken)
    {
        if (_host is { } host)
        {
            await host.StopAsync(cancellationToken);
        }

        _host = null;
    }

    /// <inheritdoc />
    public void Abort()
    {
        IHost? host = _host;
        if (host is null)
        {
            return;
        }

        using CancellationTokenSource cancellation = new();
        cancellation.Cancel(false);

        try
        {
            host.StopAsync(cancellation.Token).GetAwaiter().GetResult();
        }
        catch
        {
            // Ignore.
        }
        finally
        {
            _host = null;
        }
    }
}

類別 HostedServiceCommunicationListener 接受 Func<Task<IHost>> createHost 建構函式參數。 稍後會用來在 OpenAsync 方法中建立 IHost 執行個體。

無狀態服務專案的下一個部分是實作 StatelessService 類別。 下列範例顯示 StatelessService 類別的子類別:

using System.Fabric;
using Microsoft.Extensions.Hosting;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;

namespace ServiceFabric.HostingExample;

public sealed class OrleansHostedStatelessService : StatelessService
{
    private readonly Func<StatelessServiceContext, Task<IHost>> _createHost;

    public OrleansHostedStatelessService(
        Func<StatelessServiceContext, Task<IHost>> createHost, StatelessServiceContext serviceContext)
        : base(serviceContext) =>
        _createHost = createHost ?? throw new ArgumentNullException(nameof(createHost));  

    /// <inheritdoc/>
    protected sealed override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        // Create a listener which creates and runs an IHost
        yield return new ServiceInstanceListener(
            context => new HostedServiceCommunicationListener(() => _createHost(context)),
            nameof(HostedServiceCommunicationListener));
    }
}

在上述範例中,OrleansHostedStatelessService 類別負責產生 ICommunicationListener 執行個體。 初始化服務時,Service Fabric 執行階段會呼叫 CreateServiceInstanceListeners 方法。

將這兩個類別一起提取,下列範例會顯示完整的無狀態服務專案 Program.cs 檔案:

using System.Fabric;
using Microsoft.Extensions.Hosting;
using Microsoft.ServiceFabric.Services.Runtime;
using ServiceFabric.HostingExample;

try
{
    // The ServiceManifest.XML file defines one or more service type names.
    // Registering a service maps a service type name to a .NET type.
    // When Service Fabric creates an instance of this service type,
    // an instance of the class is created in this host process.
    await ServiceRuntime.RegisterServiceAsync(
        "Orleans.ServiceFabric.Stateless",
        context => new OrleansHostedStatelessService(
            CreateHostAsync, context));

    ServiceEventSource.Current.ServiceTypeRegistered(
        Environment.ProcessId,
        typeof(OrleansHostedStatelessService).Name);

    // Prevents this host process from terminating so services keep running.
    await Task.Delay(Timeout.Infinite);
}
catch (Exception ex)
{
    ServiceEventSource.Current.ServiceHostInitializationFailed(
        ex.ToString());
    throw;
}

static async Task<IHost> CreateHostAsync(StatelessServiceContext context)
{
    await Task.CompletedTask;

    return Host.CreateDefaultBuilder()
        .UseOrleans((_, builder) =>
        {
            // TODO, Use real storage, something like table storage
            // or SQL Server for clustering.
            builder.UseLocalhostClustering();

            // Service Fabric manages port allocations, so update the 
            // configuration using those ports. Gather configuration from 
            // Service Fabric.
            var activation = context.CodePackageActivationContext;
            var endpoints = activation.GetEndpoints();

            // These endpoint names correspond to TCP endpoints 
            // specified in ServiceManifest.xml
            var siloEndpoint = endpoints["OrleansSiloEndpoint"];
            var gatewayEndpoint = endpoints["OrleansProxyEndpoint"];
            var hostname = context.NodeContext.IPAddressOrFQDN;
            builder.ConfigureEndpoints(hostname,
                siloEndpoint.Port, gatewayEndpoint.Port);
        })
        .Build();
}

在上述程式碼中:

  • 方法 ServiceRuntime.RegisterServiceAsync 會向 Service Fabric 執行階段註冊 OrleansHostedStatelessService 類別。
  • 用於建立 IHost 執行個體的 CreateHostAsync 委派。