代码之家  ›  专栏  ›  技术社区  ›  Reddog

服务结构自删除服务

  •  0
  • Reddog  · 技术社区  · 7 年前

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

    我可以想象它将是一个无状态服务(具有集群管理权限),当它完成它的事情时,它将自动销毁。我是 under the impression that exiting the RunAsync function 允许我指示我已完成(或处于错误状态)。但是,它仍然挂在应用程序的上下文中,当它实际上根本不做任何事情时,看起来很“活跃”,让人恼火。

    服务是否可以删除自身?

    我想也许我们可以尝试使用 FabricClient.ServiceManager DeleteServiceAsync (使用基于服务上下文的参数)在 OnCloseAsync 重写,但我无法证明这可能有效,感觉有点奇怪:

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

    有更好的方法吗?

    2 回复  |  直到 7 年前
        1
  •  3
  •   masnider    7 年前

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

    关闭服务的最佳方法是调用DeleteServiceAsync。这可以由服务本身或另一个服务完成,也可以从集群外部完成。服务可以自我删除,因此对于完成工作的服务,我们通常将wait-deleteserviceasync视为runasync的最后一行,之后该方法将退出。比如:

    RunAsync(CancellationToken ct)
    {
        while(!workCompleted && !ct.IsCancellationRequested)
        {
            if(!DoneWithWork())
            {
                DoWork()
            }
    
            if(DoneWithWork())
            {
                workCompleted == true;
                await DeleteServiceAsync(...) 
            }
        }
    }
    

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

        2
  •  1
  •   Adriaan de Beer    6 年前

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