FabricNotReadableException是什么意思? 我们该如何应对呢?

我们在Service-Fabric的Stateful Service中使用以下方法。 该服务有分区。 有时我们会从这段代码中获得FabricNotReadableException。

public async Task HandleEvent(EventHandlerMessage message) { var queue = await StateManager.GetOrAddAsync<IReliableQueue>(EventHandlerServiceConstants.EventHandlerQueueName); using(ITransaction tx = StateManager.CreateTransaction()) { await queue.EnqueueAsync(tx, message); await tx.CommitAsync(); } } 

这是否意味着分区已关闭并正在移动? 我们打了一个二级分区? 因为在某些情况下还会引发FabricNotPrimaryException。

我见过MSDN链接( https://msdn.microsoft.com/en-us/library/azure/system.fabric.fabricnotreadableexception.aspx )。 但那是什么呢

表示当分区无法接受读取时引发的exception。

意思? 分区无法接受读取的情况怎么办?

在幕后,Service Fabric有几种状态可以影响给定的副本是否可以安全地提供读写操作。 他们是:

  • 当然(您可以将此视为正常操作)
  • 不是主要的
  • 没有写入仲裁(再次主要影响写入)
  • 重新配置待定

每当在当前不是主副本的副本上尝试写入时,都会抛出您提到的FabricNotPrimaryException,并映射到NotPrimary状态。

FabricNotReadableException映射到其他状态(您实际上不需要担心或区分它们),并且可能在各种情况下发生。 一个示例是,如果您尝试执行读取的副本是“备用”副本(副本已关闭且已恢复,但副本集中已有足够的活动副本)。 另一个示例是副本是主节点但是正在关闭(例如由于升级或因为它报告了故障),或者它当前正在进行重新配置(例如,正在添加另一个副本)。 由于某些安全检查和Service Fabric需要在引擎盖下处理的primefaces更改,所有这些条件都将导致副本无法满足写入的少量时间。

您可以将FabricNotReadableException视为可重复。 如果您看到它,只需再次尝试呼叫,最终它将解析为NotPrimary或​​Granted。 如果你得到FabricNotPrimaryexception,通常这应该被抛回到客户端(或以某种方式通知客户端),它需要重新解析才能找到当前的主服务器(Service Fabric发布的默认通信堆栈)观察不可重复的exception并代表您重新解决。

FabricNotReadableException目前存在两个已知问题。

  1. FabricNotReadableException应该有两个变体。 第一个应该是显式可重复的(FabricTransientNotReadableException),第二个应该是FabricNotReadableException。 第一个版本(Transient)是最常见的,可能是你遇到的,当然在大多数情况下会遇到什么。 在您最终与备用副本进行通信的情况下,将返回第二个(非瞬态)。 开箱即用的传输和重试逻辑不会与备用数据库进行通信,但是如果你有自己的,则可能遇到它。
  2. 另一个问题是今天FabricNotReadableException应该从FabricTransientException派生,这使得更容易确定正确的行为是什么。

作为答案发布(至asnider的评论 – 3月16日17:42)因为评论太长了! 🙂

我也陷入了这个问题22.我的svc启动并立即收到消息。 我想在OpenAsync中封装服务启动并设置一些ReliableDictionary值,然后开始接收消息。 但是,此时Fabric不可读,我需要在OpenAsync和RunAsync之间拆分这个“启动”:(

我服务中的OpenAsync和客户端中的OpenAsync似乎也有不同的取消令牌,所以我还需要解决如何处理这个问题。 它只是感觉有点凌乱。 我有很多关于如何在我的代码中整理它的想法,但是有没有人想出一个优雅的解决方案?

如果ICommunicationClient有一个RunAsync接口,当Fabric变得准备/可读时被调用并且当Fabric关闭副本时被取消,这将是很好的 – 这将严重简化我的生活。 🙂

我遇到了同样的问题。 我的监听器在服务的主线程之前启动。 我将需要启动的侦听器列表排队,然后在主线程中尽早激活它们。 结果,所有进入的消息都能够被处理并放入适当的可靠存储中。 我的简单解决方案(这是一个服务总线监听器):

 public Task OpenAsync (CancellationToken cancellationToken) { string uri; Start (); uri = ""; return Task.FromResult (uri); } public static object lockOperations = new object (); public static bool operationsStarted = false; public static List pendingStarts = new List (); public static void StartOperations () { lock (lockOperations) { if (!operationsStarted) { foreach (ClientAuthorizationBusCommunicationListener listener in pendingStarts) { listener.DoStart (); } operationsStarted = true; } } } private static void QueueStart (ClientAuthorizationBusCommunicationListener listener) { lock (lockOperations) { if (operationsStarted) { listener.DoStart (); } else { pendingStarts.Add (listener); } } } private void Start () { QueueStart (this); } private void DoStart () { ServiceBus.WatchStatusChanges (HandleStatusMessage, this.clientId, out this.subscription); } 

========================

在主线程中,您调用该函数来启动侦听器操作:

 protected override async Task RunAsync (CancellationToken cancellationToken) { ClientAuthorizationBusCommunicationListener.StartOperations (); 

这个问题可能在这里显现出来,因为有问题的总线已经有消息并且开始触发第二个监听器被创建。 试图访问状态管理器中的任何内容都会引发您询问的exception。