【问题标题】:Service Fabric RunAsync(CancellationToken cancellationToken) does not get cancelledService Fabric RunAsync(CancellationToken cancelToken) 不会被取消
【发布时间】:2017-01-29 07:29:50
【问题描述】:

我认为RunAsync 方法将CancellationToken 作为参数,这很棒。 不幸的是,根据我的观察,我从来没有被取消过。

当然,取消 RunAsync 方法 调用 OnCloseAsync 有点多余。 我仍然想知道取消何时(如果)实际发生。

我是否应该编写一些额外的代码来在我的客户端中提供一个有效的 Stop() 方法?我更希望 RunAsync 中的 cancelToken 实际上会被取消;-)

我的 Service Fabric 服务代码:

/// <summary>
/// This is the main entry point for your service instance.
/// </summary>
/// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service instance.</param>
protected override async Task RunAsync(CancellationToken cancellationToken)
{
    // TODO: Replace the following sample code with your own logic 
    //       or remove this RunAsync override if it's not needed in your service.

    long iterations = 0;

    while (!cancellationToken.IsCancellationRequested)
    {
        // I commented this out because I want my client to handle the cancellation 
        // event gracefully without throwing an OperationCanceled exception.
        //cancellationToken.ThrowIfCancellationRequested();

        // I never found these messages in any logs. Nor in the diagnostics events window in Visual Studio.
        ServiceEventSource.Current.ServiceMessage(this, "Working-{0}", ++iterations);

        await _client.Start(cancellationToken);

        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

我的示例客户端实现:

public class Client
{
    private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

    public async Task Start(CancellationToken cancellationToken = default(CancellationToken))
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            _logger.Info("Saying hello from Main Operation.");
            await Task.Delay(3000, cancellationToken);
        }

        _logger.Info("Cancellation requested. Shutting down MainOperation().");
    }

    public void Stop()
    {
        _logger.Info("Stop requested. But I have no means to stop. Not implemented.");
    }
}

【问题讨论】:

  • 同样,一种方法是在完成后以编程方式删除服务,使用 DeleteServiceAsync 您也可以使用 CreateServiceAsync 重新创建它。
  • 当然。但我不想在 Service Fabric 之外运行任何代码。还调用了 OnCloseAsync,这很好。我可以使用它。我仍然想知道 RunAsync 的 cancelToken 何时被设置为“cancel”。
  • 您可以从其他服务调用它。它在服务停止、升级、从辅助副本移动到主副本和/或在集群中重新定位时调用。
  • 你如何从另一个服务中调用这个取消?有人可以帮助了解取消令牌在那种情况下的用法吗?
  • 我自己没有尝试过,但您可以使用例如Service Fabric ManagerPowerShell。如果您忽略 RunAsync 中的取消令牌,则服务结构服务无法正常关闭

标签: c# azure-service-fabric


【解决方案1】:

是的,取消令牌实际上已取消。这是有保证的。我可以向您保证,经过多年的测试和生产使用,这不是疏忽。

但是您的代码中存在疏忽。

如果您希望从客户端看到此跟踪输出:

 _logger.Info("Cancellation requested. Shutting down MainOperation().");

你不会,而是不太可能你会看到它。为什么?因为它之前的这一行:

await Task.Delay(3000, cancellationToken);

当在延迟期间发出取消令牌信号时,将抛出 OperationCanceledException。这将使您退出循环并退出 RunAsync,因此您的日志记录行将不会执行。

由于您在该延迟中花费了 3 秒,并且在循环之外花费了纳秒,您可以看到为什么当您不在延迟之内时取消发生的可能性极小。

【讨论】:

  • 如果服务结构包含带有 CancellationToken 的 RunAsync,为什么会有 CloseAsync?您知道RunAsync 中的 CancellationToken 何时关闭服务吗?
  • 如果无状态服务将关闭,则将在每个侦听器上调用 CloseAsync()。同时,取消令牌被传递给 RunAsync()。如果两者都完成,则调用无状态服务的 OnCloseAsync() 方法来停止后台进程等。您也可以在 RunAsync 中实现它,但有时您必须确保所有侦听器都已关闭,或者有时它只是更清晰/更具可读性。 docs.microsoft.com/en-us/azure/service-fabric/…
猜你喜欢
  • 1970-01-01
  • 2018-06-06
  • 2017-05-13
  • 2017-12-25
  • 1970-01-01
  • 1970-01-01
  • 2016-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多