0

我想添加一个服务,在系统首次创建时执行一些初始化操作。

我想这将是一个无状态服务(具有集群管理员权限),它应该在完成后自毁。我的印象是退出该RunAsync功能可以让我表明我已经完成(或处于错误状态)。然而,它仍然在应用程序的上下文中徘徊,并且在它根本没有真正做任何事情时看起来像是“活跃的”。

服务是否可以自行删除?

我想也许我们可以尝试在覆盖中使用FabricClient.ServiceManager's DeleteServiceAsync(使用基于服务上下文的参数),OnCloseAsync但我无法证明这可能有效,而且感觉有点时髦:

var client = new FabricClient();
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(Context.ServiceName));

有没有更好的办法?

4

2 回答 2

4

从 RunAsync 返回将结束 RunAsync 中的代码(表示完成),因此 SF 不会再次启动 RunAsync(例如,如果它返回异常,则会启动)。RunAsync 完成不会导致服务被删除。如前所述,例如,该服务可能通过后台工作完成,但仍在侦听传入消息。

关闭服务的最佳方法是调用 DeleteServiceAsync。这可以由服务本身或其他服务完成,也可以从集群外部完成。服务可以自行删除,因此对于工作完成的服务,我们通常将 await DeleteServiceAsync 视为 RunAsync 的最后一行,之后该方法就退出了。就像是:

RunAsync(CancellationToken ct)
{
    while(!workCompleted && !ct.IsCancellationRequested)
    {
        if(!DoneWithWork())
        {
            DoWork()
        }

        if(DoneWithWork())
        {
            workCompleted == true;
            await DeleteServiceAsync(...) 
        }
    }
}

目标是确保如果您的服务确实完成了它自己清理的工作,但不会因为 CancellationToken 可以收到信号的其他原因触发自己的删除,例如由于某些升级或集群资源而关闭平衡。

于 2018-05-21T22:53:35.243 回答
1

如前所述,从 RunAsync 返回只会结束此方法,但服务将继续运行,因此不会被删除。

DeleteServiceAsync当然是要走的路 - 但是它并不像调用它那么简单,因为如果你不小心它会在当前线程上死锁(尤其是在本地开发人员集群中)。您还可能会收到一些关于 RunAsync 需要很长时间才能终止和/或未达到目标副本大小的短期健康警告。

无论如何 - 解决方案非常简单 - 只需这样做:

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)将有助于解决死锁问题,因为它本质上将返回到一个新的线程同步上下文 - 即不尝试返回到“调用者上下文”。

于 2018-10-19T01:17:24.127 回答