Узел с Service Fabric
Orleans можно разместить в Azure Service Fabric с помощью Microsoft.ServiceFabric.Services и Microsoft.Orleans. Пакеты NuGet сервера . Силосы должны размещаться как непараментированные, службы без отслеживания состояния, так как Orleans управляет распределением сам по себе зерна. Другие варианты размещения, такие как секционированные и отслеживание состояния, являются более сложными и не дают никаких преимуществ без дополнительной настройки для части разработчика. Рекомендуется размещать Orleans безсекционные и без отслеживания состояния.
Служба без отслеживания состояния Service Fabric в качестве Silo
Независимо от того, создаете ли вы новое приложение Service Fabric или добавляете Orleans в существующий, вам потребуется как ссылки на Microsoft.ServiceFabric.Services
пакеты, так и Microsoft.Orleans.Server
ссылки на пакеты в проекте. Для проекта службы без отслеживания состояния требуется реализация ICommunicationListener в подклассе.StatelessService
Жизненный цикл Silo следует типичному жизненному циклу прослушивателя связи:
- Он инициализирован с ICommunicationListener.OpenAsyncпомощью .
- Это корректно завершается ICommunicationListener.CloseAsync.
- Или это резко заканчивается ICommunicationListener.Abort.
Так как Orleans Силосы способны жить в пределах границ IHost, реализация ICommunicationListener
является оболочкой вокруг IHost
. Инициализируется IHost
в методе OpenAsync
и корректно завершается в методе CloseAsync
:
ICommunicationListener |
IHost Взаимодействия |
---|---|
OpenAsync | Создается IHost экземпляр и выполняется вызов StartAsync . |
CloseAsync | Ожидается вызов StopAsync экземпляра узла. |
Abort | Вызов StopAsync принудительно вычисляется, с GetAwaiter().GetResult() . |
Поддержка кластера
Официальная поддержка кластеризация доступна из различных пакетов, включая:
- Microsoft.Orleans. Clustering.Azure служба хранилища
- Microsoft.Orleans. Clustering.AdoNet
- Microsoft.Orleans. Clustering.DynamoDB
Существует также несколько сторонних пакетов, доступных для других служб, таких как 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
. Это позже используется для создания IHost
экземпляра в методе OpenAsync
.
Следующая часть проекта службы без отслеживания состояния — реализация 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
. Метод CreateServiceInstanceListeners
вызывается средой выполнения Service Fabric при инициализации службы.
Вытягивание этих двух классов вместе, в следующем примере показан полный проект службы без отслеживания состояния 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 регистрирует
OrleansHostedStatelessService
класс в среде выполнения Service Fabric. - Делегат
CreateHostAsync
используется для создания экземпляраIHost
.