使用 Service Fabric 託管
可以使用 Microsoft.ServiceFabric.Services 和 Microsoft.Orleans.Server NuGet 套件,在 Azure Service Fabric 上託管 Orleans。 定址接收器應該託管為未分割的無狀態服務,因為 Orleans 會管理精細度本身的分佈。 其他託管選項 (例如分割和具狀態方式) 會比較複雜,如果開發人員端未進行額外的自訂,則不會帶來任何益處。 建議您以未分割和無狀態的方式託管 Orleans。
作為定址接收器的 Service Fabric 無狀態服務
無論您是建立新的 Service Fabric 應用程式或將 Orleans 新增至現有的 Service Fabric 應用程式,您都需要專案中的 Microsoft.ServiceFabric.Services
和 Microsoft.Orleans.Server
套件參考。 無狀態服務專案需要在 ICommunicationListener 和 StatelessService 子類別上實作。
定址接收器生命週期遵循典型的通訊接聽程式生命週期:
- 使用 ICommunicationListener.OpenAsync 進行初始化。
- 使用 ICommunicationListener.CloseAsync 以正常方式終止。
- 或使用 ICommunicationListener.Abort 突然終止。
由於 Orleans 定址接收器能夠在 IHost 的範圍運作,所以 ICommunicationListener
的實作是在 IHost
周圍的包裝函式。 會在 OpenAsync
方法中初始化 IHost
,並在 CloseAsync
方法中正常終止:
ICommunicationListener |
IHost 互動 |
---|---|
OpenAsync | 系統會建立 IHost 執行個體,並呼叫 StartAsync。 |
CloseAsync | 等候在主機執行個體上呼叫 StopAsync。 |
Abort | 使用 GetAwaiter().GetResult() 強制評估對 StopAsync 的呼叫。 |
叢隻支援
您可從各種套件取得官方叢集支援,包括:
- 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));
}
}
在上述範例中,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
委派。