Service Fabric的RunAsync(CancellationToken cancellationToken)方法无法被取消。

6
我发现RunAsync方法需要一个CancellationToken作为参数,这很好。不幸的是,根据我的观察,它从未被取消。
当然取消RunAsync方法并调用OnCloseAsync可能有点多余。但我仍然想知道(如果)取消实际上何时发生。
我需要编写一些额外的代码来提供工作中的Stop()方法吗?我更希望在RunAsync中的cancellationToken实际上会被取消;-)
我的Service Fabric Service代码:
/// <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重新创建它。 - LoekD
当然可以。但是我不想在Service Fabric之外运行任何代码。而且OnCloseAsync正在被调用,这很好。我可以处理它。但我仍然想知道RunAsync的cancellationToken何时被设置为“cancel”。 - lapsus
您可以从另一个服务中调用它。当服务停止、需要升级、从辅助副本移动到主副本和/或在集群中重新定位时,它会被调用。 - LoekD
你怎么从另一个服务中调用这个取消操作?有人能帮忙理解在那种情况下如何使用CancellationToken吗? - swcraft
我自己没有尝试过,但你可以使用例如Service Fabric ManagerPowerShell。如果你在RunAsync中忽略了取消令牌,那么服务织物服务将无法正常关闭。 - Boologne
1个回答

9

是的,取消令牌确实被取消了。这是有保证的。我可以向您保证,在多年的测试和生产使用中,这不是疏忽。

然而,您的代码存在一个疏忽。

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

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

你不会看到它,实际上你几乎不可能看到它。为什么?因为在它之前有这样一行代码:

await Task.Delay(3000, cancellationToken);

当取消标记在延迟期间被触发时,会抛出OperationCanceledException异常。这将使您退出循环和RunAsync,因此您的日志记录行将不会执行。

由于您在延迟中花费了3秒钟,在循环外花费了纳秒级别的时间,因此您可以看到在您不在延迟期间时取消操作的可能性极小。


如果Service Fabric包含带有CancellationToken的RunAsync,为什么还需要CloseAsync?你知道通过RunAsync中的CancellationToken服务何时关闭,对吧? - The Muffin Man
如果无状态服务将关闭,则会在每个侦听器上调用CloseAsync()。同时,取消令牌被传递给RunAsync()。如果两者都完成,则调用无状态服务的OnCloseAsync()方法以停止后台进程等。 您也可以将其实现到RunAsync中,但有时必须确保所有侦听器都已关闭,有时只是更清晰/更易读。 https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-lifecycle - Boologne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接