You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Service Fabric滚动升级中cancellationToken.IsCancellationRequested未生效

解决Stateful Service滚动升级时循环卡住并持续抛"Primary State Manager is currently not readable"异常的问题

首先,咱们先拆解下你遇到的问题:滚动升级时,Service Fabric本应该触发RunAsync的取消令牌让循环退出,但你的代码因为没正确处理取消信号+异常捕获逻辑的问题,导致循环一直跑,反复抛出State Manager不可读的异常,同时Service Fabric Explorer里会显示类似**"Replica is undergoing reconfiguration, please wait for the reconfiguration to complete"**的提示(对应你提供的截图内容)。

问题根源分析

  • 取消令牌未被及时检查:你的循环只在开头判断!cancellationToken.IsCancellationRequested,但当升级触发取消后,若await this.cacheStore.GetAllCacheItemsWithExpiration()抛出异常,catch块仅记录异常就回到循环开头,此时如果取消令牌已经触发,却没再次确认状态,就会导致循环继续执行。
  • 未将取消令牌传递给Reliable Collection操作:GetAllCacheItemsWithExpiration方法内部可能没有接收cancellationToken,导致Service Fabric发送取消信号后,这个异步操作还在等待,无法及时终止。
  • 未处理特定异常的重试/退出逻辑:"Primary State Manager is currently not readable"是副本重新配置时的临时状态,这时候应该重试,但重试前必须检查取消令牌,避免无限重试。

修复方案

修改你的RunAsync代码,做以下调整:

while (!cancellationToken.IsCancellationRequested) 
{ 
    try 
    { 
        // 把取消令牌传递给Reliable Collection操作,让它能响应取消
        var cacheItemsWithExpiration = await this.cacheStore.GetAllCacheItemsWithExpiration(cancellationToken); 
        // some processing on cacheItemsWithExpiration 
    } 
    catch (FabricTransientException ex) when (ex.Message.Contains("Primary State Manager is currently not readable"))
    {
        // 针对临时不可读的异常,添加短时间重试,同时检查取消令牌
        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
        this.telemetryHelper.TrackException(ex);
    }
    catch (Exception ex) 
    { 
        this.telemetryHelper.TrackException(ex); 
        // 捕获其他异常后,再次检查取消令牌,避免循环卡住
        if (cancellationToken.IsCancellationRequested)
        {
            break;
        }
        // 可选:添加其他异常的重试逻辑,根据业务需求调整
        await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
    } 
    // 循环末尾也检查一次取消令牌,确保及时退出
    if (cancellationToken.IsCancellationRequested)
    {
        break;
    }
}

同时,需要修改GetAllCacheItemsWithExpiration方法,让它接收并使用cancellationToken,比如在内部调用Reliable Collection的方法时传入令牌:

public async Task<IEnumerable<CacheItem>> GetAllCacheItemsWithExpiration(CancellationToken cancellationToken)
{
    var reliableDict = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, CacheItem>>("CacheStore");
    using (var tx = this.StateManager.CreateTransaction())
    {
        // 传递取消令牌给异步枚举操作
        var enumerator = await reliableDict.CreateEnumerableAsync(tx, cancellationToken);
        var items = new List<CacheItem>();
        while (await enumerator.MoveNextAsync(cancellationToken))
        {
            items.Add(enumerator.Current.Value);
        }
        return items.Where(item => item.ExpirationTime <= DateTime.UtcNow);
    }
}

额外注意事项

  • Service Fabric升级时的副本行为:滚动升级时,Service Fabric会先将旧版本的副本标记为要关闭,触发RunAsync的取消令牌,然后启动新版本副本。如果旧副本的RunAsync不能及时退出,会导致升级卡住或超时。
  • 避免无限制的异常循环:一定要在异常处理逻辑中检查取消令牌,确保在收到取消信号后能立即退出循环,不要因为异常捕获而忽略了取消请求。

内容的提问来源于stack exchange,提问作者Dadwals

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:07:10