Dela via


Värd med Service Fabric

Orleans kan finnas i Azure Service Fabric med hjälp av Microsoft.ServiceFabric.Services och Microsoft.Orleans. Server NuGet-paket. Silos ska vara värd för icke-partitionerade, tillståndslösa tjänster eftersom Orleans de hanterar fördelningen av själva kornen. Andra värdalternativ, till exempel partitionerade och tillståndskänsliga, är mer komplexa och ger inga fördelar utan ytterligare anpassning från utvecklarens sida. Vi rekommenderar att du är värd Orleans för opartitionerad och tillståndslös.

Tillståndslös Service Fabric-tjänst som Silo

Oavsett om du skapar ett nytt Service Fabric-program eller lägger Orleans till ett befintligt, behöver du både paketreferenserna Microsoft.ServiceFabric.Services och Microsoft.Orleans.Server i projektet. Det tillståndslösa tjänstprojektet behöver en implementering av ICommunicationListener och en underklass av StatelessService.

Silo-livscykeln följer den typiska livscykeln för kommunikationslyssnare:

Eftersom Orleans Silos kan leva inom gränserna för IHost, är implementeringen av ICommunicationListener en wrapper runt IHost. IHost Initieras i OpenAsync -metoden och avslutas korrekt i CloseAsync -metoden:

ICommunicationListener IHost Interaktioner
OpenAsync Instansen IHost skapas och ett anrop till StartAsync görs.
CloseAsync Ett anrop till StopAsync på värdinstansen väntar.
Abort Ett anrop till StopAsync utvärderas kraftfullt med GetAwaiter().GetResult().

Klusterstöd

Officiellt stöd för klustring är tillgängligt från olika paket, inklusive:

Det finns också flera tredjepartspaket tillgängliga för andra tjänster som CosmosDB, Kubernetes, Redis och Aerospike. Mer information finns i Klusterhantering i Orleans.

Exempelprojekt

I det tillståndslösa tjänstprojektet implementerar du ICommunicationListener gränssnittet enligt följande exempel:

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;
        }
    }
}

Klassen HostedServiceCommunicationListener accepterar en Func<Task<IHost>> createHost konstruktorparameter. Detta används senare för att skapa instansen IHost OpenAsync i -metoden.

Nästa del av det tillståndslösa tjänstprojektet är att implementera StatelessService klassen. I följande exempel visas klassens StatelessService underklass:

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));
    }
}

I föregående exempel OrleansHostedStatelessService ansvarar klassen för att ge en ICommunicationListener instans. Metoden CreateServiceInstanceListeners anropas av Service Fabric-körningen när tjänsten initieras.

När de här två klasserna samlas visar följande exempel det fullständiga tillståndslösa tjänstprojektet Program.cs fil:

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();
}

I koden ovan:

  • Metoden ServiceRuntime.RegisterServiceAsync registrerar OrleansHostedStatelessService klassen med Service Fabric-körningen.
  • Ombudet CreateHostAsync används för att skapa instansen IHost .