Service Fabric を使用してホストする
Orleans は、Microsoft.ServiceFabric.Services および Microsoft.Orleans.Server NuGet パッケージを使用して Azure Service Fabric 上でホストすることができます。 グレイン自体の分散は Orleans によって管理されるため、サイロはパーティション分割されていないステートレス サービスとしてホストする必要があります。 パーティション分割やステートフルなどの他のホスティング オプションはいっそう複雑であり、開発者がさらにカスタマイズしないとメリットは得られません。 Orleans は、パーティション分割せず、ステートレスとしてホストすることが推奨されます。
サイロとしての Service Fabric ステートレス サービス
新しい Service Fabric アプリケーションを作成する場合でも、既存のアプリケーションに Orleans を追加する場合でも、プロジェクトには Microsoft.ServiceFabric.Services
と Microsoft.Orleans.Server
の両方のパッケージ参照が必要です。 ステートレス サービス プロジェクトには、ICommunicationListener での実装と StatelessService のサブクラスが必要です。
サイロのライフサイクルは、一般的な通信リスナーのライフサイクルに従います。
- 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.AzureStorage
- 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
コンストラクター パラメーターを受け取ります。 これは、後ほど、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));
}
}
前の例では、ICommunicationListener
インスタンスの生成は OrleansHostedStatelessService
クラスで行われます。 CreateServiceInstanceListeners
メソッドは、サービスが初期化されるときに Service Fabric ランタイムによって呼び出されます。
これら 2 つのクラスをまとめた次の例では、完全なステートレス サービス プロジェクトの 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
インスタンスの作成に使われます。
.NET