在服务结构服务中存储取消令牌

Posted

技术标签:

【中文标题】在服务结构服务中存储取消令牌【英文标题】:store cancellation tokens in service fabric services 【发布时间】:2019-03-30 15:07:11 【问题描述】:

我正在尝试在服务结构有状态服务中实现取消任务功能。

计划正在使用取消令牌将通知传播到链接的线程/任务。

问题是,虽然有这些长时间运行的任务和线程在等待这个信号,但我不确定如何根据另一个 Web API 调用找到正确的取消令牌。

我正在考虑使用可靠的字典,然后甚至在尝试之前,我认为这会遇到死胡同,因为cancellationToken 无法序列化/反序列化。

请帮助我解决这个问题的好方法。

更新(我不想创建一个新线程丢失该线程中提到的一些重要上下文,所以在这篇文章中更新。)

确认下面的链接描述确实显示了可靠的服务和参与者方法可以支持取消令牌。然而,典型的用例是直接通过 Web API 接收取消请求,用户触发,例如点击刷新、转到另一个页面等。在这种情况下,完全相同的端点需要接收请求,而之前的 http 请求仍然存在一些长时间运行的任务或卡住。这不是这个线程中的场景。

来自链接:https://blogs.msdn.microsoft.com/azureservicefabric/2016/02/23/service-fabric-sdk-v1-5-175-and-the-adoption-of-virtual-machine-scale-sets/

对 IService/IActor 的 CancellationToken 支持

Reliable Service 和 Reliable Actor 方法现在支持可以通过 ActorProxy 和 ServiceProxy 远程访问的取消令牌,允许您实现协作取消。想要取消长时间运行的服务或参与者方法的客户端可以发出取消令牌的信号,并且取消意图将传播到参与者/服务方法。然后,该方法可以通过查看其取消令牌参数的状态来确定何时停止执行。

例如,一个参与者的合约可能有一个可能长时间运行的方法,可以如下建模:

        public interface IPrimeNumberActorInterface : IActor
        

            Task<ulong> FindNextPrimeNumberAsync
                (ulong previous, CancellationToken cancellationToken);

        

希望取消方法执行的客户端代码可以通过取消取消令牌来传达其意图。

【问题讨论】:

【参考方案1】:

CancellationTokenCancellationTokenSource 不可序列化,并且不会在 SF 中的服务调用或数据复制之间流动。它只能用于告诉同一进程中的处理程序一个操作已被取消,并且在收到响应时应该停止任何处理或忽略任何继续。

如果您希望能够在另一个服务中启动和取消操作,您应该将操作拆分为两个调用。

首先会生成一个Operation ID返回给客户端,并为此操作创建CancellationTokenSource生成CancellationToken传递给后台运行的Task\Thread 第二个将接收 OperationID 并识别 CancellationTokenSource 是否存在并取消它,以便提供给任何 Task\Thread 的令牌可以停止任何处理(如果尚未完成或取消)。

您可以简单地将其作为Dictionary&lt;Guid, CancellationTokenSource&gt; 存储在运行任务的进程\分区中。

如果您在 SF 的多个分区中运行这些任务,并计划将其存储在 Reliable Dictionary 中,这不是一个好主意,因为如前所述,您无法将取消序列化到其他分区。

在这种情况下,您可以存储 OperationID 和 PartitionID,因此所有分区都知道操作在哪里运行,当您在任何分区上收到取消调用时,服务将在这个可靠的字典中查找操作所在的位置运行并将取消转发到正确的分区。

【讨论】:

我找到了一篇使用 ISerializationSurrogate 的文章。 blogs.msdn.microsoft.com/schlepticons/2008/08/24/… 尚不确定这是否可行并实现序列化自定义序列化取消令牌。如果不是,那么您建议的可能是一个选项.. 不幸的是,使用上述链接方法的反序列化取消令牌丢失了所有注册的回调,可能它甚至不会与传递给其他线程的引用相同.. 值得检查。跨度> 在你写的“在这种情况下你可以存储 OperationID 和 PartitionID”,你的意思是可靠的字典吗?在我的情况下,取消令牌不是归结为内置提供的功能,例如 RunAsync(cancellationtoken),而是我必须在生成的线程中创建的一个(新的取消令牌来杀死演员/任务)..想知道我怎么能达到这些令牌调用 Cancel()。此外,如果您可以通过将取消转发到正确的分区来解释更多细节,这将是非常有帮助的.. 只有运行该操作的进程(服务分区)可以取消它,在这种情况下,您将在同一个进程中存储带有取消令牌的字典。具有 operationID 和 PartitionID 的可靠字典可以存储在任何地方,例如,在 API 中,因为您必须将取消请求发送到运行该操作的进程(服务分区)。 client\caller会向API发送cancel命令,API会找到哪个partition有进程并调用service,service接收到cancel token的请求 OperationId 不是你找到的,在上面提出的想法中,OperationID 是你生成的用于标识正在运行的操作的 ID,int 不是 Service Fabric 生成的,Service Fabric 只是你的编排器服务,它对上面提到的设计影响很小。因为您最初的问题是询问如何解决“解决方案”而不是“如何解决问题”,所以很难用与您所问的完全不同的东西来回答。我建议您提出另一个关于“如何使用 Service Fabric 取消远程操作”的问题

以上是关于在服务结构服务中存储取消令牌的主要内容,如果未能解决你的问题,请参考以下文章

链接取消令牌

在 ActivateAsync 上取消服务结构参与者激活?

如何识别和删除服务器上过期的 FCM 令牌?

服务器端 C# Websocket,如何在监听取消令牌时运行循环?

如何使用取消令牌停止范围服务?

AccountManager 的应用流程