Service Fabric RunAsync(CancellationToken cancellationToken) 没有被取消

Service Fabric RunAsync(CancellationToken cancellationToken) does not get cancelled

我认为 RunAsync 方法采用 CancellationToken 作为参数,这很棒。 不幸的是,根据我的观察,我从未被取消。

当然,取消 RunAsync 方法 调用 OnCloseAsync 有点多余。 我仍然想知道什么时候(如果)取消真的发生了。

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

我的服务结构服务代码:

/// <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.");
    }
}

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

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

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

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

你不会,而是极度你永远不会看到它。为什么?因为它前面的这一行:

await Task.Delay(3000, cancellationToken);

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

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