Service Fabric 自删除服务
Service Fabric self-deleting service
我想添加一个服务,在系统首次创建时为系统执行一些初始化操作。
我想这将是一个无状态服务(具有集群管理员权限),它应该在完成后自毁。我是 under the impression that exiting the RunAsync
function 允许我指示我已完成(或处于错误状态)。但是,它仍然在应用程序的上下文中徘徊,并且看起来很烦人 "active" 当它根本没有做任何事情时。
服务是否可以自行删除?
我想也许我们可以尝试在 OnCloseAsync
覆盖中使用 FabricClient.ServiceManager
的 DeleteServiceAsync
(使用基于服务上下文的参数),但我无法做到证明这可能有效并且感觉有点古怪:
var client = new FabricClient();
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(Context.ServiceName));
有没有更好的方法?
从 RunAsync 返回将结束 RunAsync 中的代码(表示完成),因此 SF 不会再次启动 RunAsync(例如,如果它返回异常,它会启动)。 RunAsync 完成不会导致 service 被删除。例如,如前所述,该服务可能通过后台工作完成,但仍在侦听传入消息。
关闭服务的最佳方法是调用 DeleteServiceAsync。这可以由服务本身或其他服务完成,也可以从集群外部完成。服务可以自行删除,因此对于已完成工作的服务,我们通常会在 RunAsync 的最后一行看到等待 DeleteServiceAsync,之后该方法就会退出。类似于:
RunAsync(CancellationToken ct)
{
while(!workCompleted && !ct.IsCancellationRequested)
{
if(!DoneWithWork())
{
DoWork()
}
if(DoneWithWork())
{
workCompleted == true;
await DeleteServiceAsync(...)
}
}
}
目标是确保如果您的服务确实完成了工作,它会自行清理,但不会因为 CancellationToken 可以收到信号的其他原因而触发自己的删除,例如由于以下原因而关闭一些升级或集群资源平衡。
如前所述,从 RunAsync returning 只会结束此方法,但服务将继续 运行,因此不会被删除。
DeleteServiceAsync
当然是要走的路 - 但是它并不像调用它那么简单,因为如果你不小心它会在当前线程上死锁(特别是在本地开发人员集群中)。您还可能会收到一些关于 RunAsync 需要很长时间才能终止的短暂健康警告 and/or 未满足目标副本大小。
无论如何 - 解决方案非常简单 - 只需这样做:
private async Task DeleteSelf(CancellationToken cancellationToken)
{
using (var client = new FabricClient())
{
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(this.Context.ServiceName), TimeSpan.FromMinutes(1), cancellationToken);
}
}
然后,在我调用的 RunAsync 方法的最后一行中:
await DeleteSelf(cancellationToken).ConfigureAwait(false);
ConfigureAwait(false)
将有助于解决死锁问题,因为它本质上会 return 到一个新的线程同步上下文 - 即不会尝试 return 到 "caller context"。
我想添加一个服务,在系统首次创建时为系统执行一些初始化操作。
我想这将是一个无状态服务(具有集群管理员权限),它应该在完成后自毁。我是 under the impression that exiting the RunAsync
function 允许我指示我已完成(或处于错误状态)。但是,它仍然在应用程序的上下文中徘徊,并且看起来很烦人 "active" 当它根本没有做任何事情时。
服务是否可以自行删除?
我想也许我们可以尝试在 OnCloseAsync
覆盖中使用 FabricClient.ServiceManager
的 DeleteServiceAsync
(使用基于服务上下文的参数),但我无法做到证明这可能有效并且感觉有点古怪:
var client = new FabricClient();
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(Context.ServiceName));
有没有更好的方法?
从 RunAsync 返回将结束 RunAsync 中的代码(表示完成),因此 SF 不会再次启动 RunAsync(例如,如果它返回异常,它会启动)。 RunAsync 完成不会导致 service 被删除。例如,如前所述,该服务可能通过后台工作完成,但仍在侦听传入消息。
关闭服务的最佳方法是调用 DeleteServiceAsync。这可以由服务本身或其他服务完成,也可以从集群外部完成。服务可以自行删除,因此对于已完成工作的服务,我们通常会在 RunAsync 的最后一行看到等待 DeleteServiceAsync,之后该方法就会退出。类似于:
RunAsync(CancellationToken ct)
{
while(!workCompleted && !ct.IsCancellationRequested)
{
if(!DoneWithWork())
{
DoWork()
}
if(DoneWithWork())
{
workCompleted == true;
await DeleteServiceAsync(...)
}
}
}
目标是确保如果您的服务确实完成了工作,它会自行清理,但不会因为 CancellationToken 可以收到信号的其他原因而触发自己的删除,例如由于以下原因而关闭一些升级或集群资源平衡。
如前所述,从 RunAsync returning 只会结束此方法,但服务将继续 运行,因此不会被删除。
DeleteServiceAsync
当然是要走的路 - 但是它并不像调用它那么简单,因为如果你不小心它会在当前线程上死锁(特别是在本地开发人员集群中)。您还可能会收到一些关于 RunAsync 需要很长时间才能终止的短暂健康警告 and/or 未满足目标副本大小。
无论如何 - 解决方案非常简单 - 只需这样做:
private async Task DeleteSelf(CancellationToken cancellationToken)
{
using (var client = new FabricClient())
{
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(this.Context.ServiceName), TimeSpan.FromMinutes(1), cancellationToken);
}
}
然后,在我调用的 RunAsync 方法的最后一行中:
await DeleteSelf(cancellationToken).ConfigureAwait(false);
ConfigureAwait(false)
将有助于解决死锁问题,因为它本质上会 return 到一个新的线程同步上下文 - 即不会尝试 return 到 "caller context"。