Host com Service Fabric
Orleanspode ser hospedado no Azure Service Fabric usando Microsoft.ServiceFabric.Services e Microsoft.Orleans. Pacotes NuGet do servidor. Os silos devem ser hospedados como serviços não particionados e sem estado, uma vez que Orleans gerencia a distribuição dos próprios grãos. Outras opções de hospedagem, como particionado e stateful, são mais complexas e não geram benefícios sem personalização adicional por parte do desenvolvedor. Recomenda-se hospedar Orleans não particionado e sem monitoração de estado.
Serviço sem estado do Service Fabric como um silo
Quer esteja criando um novo aplicativo do Service Fabric ou adicionando Orleans a um existente, você precisará das Microsoft.ServiceFabric.Services
referências e Microsoft.Orleans.Server
do pacote em seu projeto. O projeto de serviço sem estado precisa de uma implementação na ICommunicationListener e uma subclasse do StatelessService.
O ciclo de vida do Silo segue o ciclo de vida típico do ouvinte de comunicação:
- É inicializado com ICommunicationListener.OpenAsync.
- É graciosamente terminado com ICommunicationListener.CloseAsync.
- Ou é abruptamente encerrado com ICommunicationListener.Abort.
Uma vez que Orleans os silos são capazes de viver dentro dos limites do IHost, a implementação do ICommunicationListener
é um invólucro em torno do IHost
. O IHost
é inicializado no OpenAsync
método e terminado graciosamente no CloseAsync
método:
ICommunicationListener |
IHost Interações |
---|---|
OpenAsync | A IHost instância é criada e uma chamada para StartAsync é feita. |
CloseAsync | Aguarda-se uma chamada para StopAsync na instância do host. |
Abort | Uma chamada para StopAsync é avaliada com força, com GetAwaiter().GetResult() . |
Suporte a clusters
O suporte oficial ao clustering está disponível a partir de vários pacotes, incluindo:
- Microsoft.Orleans. Clustering.AzureStorage
- Microsoft.Orleans. Clustering.AdoNet
- Microsoft.Orleans. Clustering.DynamoDB
Há também vários pacotes de terceiros disponíveis para outros serviços, como CosmosDB, Kubernetes, Redis e Aerospike. Para obter mais informações, consulte Gerenciamento de cluster em Orleans.
Exemplo de projeto
No projeto de serviço sem estado, implemente a ICommunicationListener
interface conforme mostrado no exemplo a seguir:
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;
}
}
}
A HostedServiceCommunicationListener
classe aceita um Func<Task<IHost>> createHost
parâmetro do construtor. Isso é usado posteriormente para criar a IHost
instância no OpenAsync
método.
A próxima parte do projeto de serviço sem estado é implementar a StatelessService
classe. O exemplo a seguir mostra a subclasse da StatelessService
classe:
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));
}
}
No exemplo anterior, a OrleansHostedStatelessService
classe é responsável por produzir uma ICommunicationListener
instância. O CreateServiceInstanceListeners
método é chamado pelo tempo de execução do Service Fabric quando o serviço é inicializado.
Juntando essas duas classes, o exemplo a seguir mostra o projeto de serviço sem estado completo Program.cs arquivo:
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();
}
No código anterior:
- O ServiceRuntime.RegisterServiceAsync método registra a
OrleansHostedStatelessService
classe com o tempo de execução do Service Fabric. - O
CreateHostAsync
delegado é usado para criar aIHost
instância.