【问题标题】:Automatically expire Service Fabric Reliable Dictionary objects via RunAsync通过 RunAsync 自动使 Service Fabric Reliable Dictionary 对象过期
【发布时间】:2017-05-13 06:18:14
【问题描述】:

我正在尝试向过期的可靠字典对象添加自动删除功能,看起来我必须按照自己的方式实现:https://stackoverflow.com/a/36466890/7293543

我的方法是使用“RunAsync”任务并让它不断地运行一个while循环。它在前几次有效,但是一旦我向字典中添加了更多对象,我就会遇到一个奇怪的错误。这是一种愚蠢的方法吗?其他人如何自动清除他们可靠的字典对象?

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();
        await deleteExpired("MyDictionaryName", cancellationToken);
    }
}

private async Task deleteExpired(string dictionaryName, CancellationToken cancellationToken)
{
    var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, CacheObject>>(dictionaryName);
    Dictionary<string, CacheObject> ret = new Dictionary<string, CacheObject>();

    using (var tx = StateManager.CreateTransaction())
    {
        var count = myDictionary.GetCountAsync(tx);

        if (count.Result > 0)
        {
            IAsyncEnumerator<KeyValuePair<string, CacheObject>> e = (await myDictionary.CreateEnumerableAsync(tx)).GetAsyncEnumerator();

            while (await e.MoveNextAsync(cancellationToken))
            {
                if (e.Current.Value.expiration <= DateTime.Now)
                {
                    await myDictionary.TryRemoveAsync(tx, e.Current.Key);
                    await tx.CommitAsync();
                    ServiceEventSource.Current.ServiceMessage(this.Context, String.Format("Object deleted at {0} - key: {1} expired at {2}", DateTime.Now.ToString(), e.Current.Key, e.Current.Value.expiration.ToString()));
                }
            }
        }
    }
}

错误: 在我将一些可靠的字典对象添加到我的字典中后,错误发生在“while(true)”上。

托管调试助手“FatalExecutionEngineError”检测到“C:\SfDevCluster\Data_App_Node_2\CacheApplicationType_App339\CachePkg.Code.1.0.0\Cache.exe”存在问题。

附加信息:运行时遇到致命错误。错误地址位于线程 0x1980 上的 0x8c46ed90。错误代码为 0x80131623。此错误可能是 CLR 或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM-interop 或 PInvoke 的用户封送错误,这可能会损坏堆栈。

【问题讨论】:

  • 我在您的代码中没有看到任何while (true),您怎么知道错误发生在while (true),而这显然是您的流程中的致命错误,而不是.NET 异常一个堆栈跟踪,可让您了解失败的代码部分?我认为您的代码中没有任何内容会产生这样的错误,所以我的猜测是该错误与您发布的代码无关,或者您在 Service Fabric 中遇到了错误。
  • 与错误无关,但 1.CommitAsync 应该在内部 while 循环之后(提交后不能使用事务)。 2.在await deleteExpired..之后添加一些延迟await Task.Delay(...)。 3. 不建议在同一事务中混用单实体和多实体操作。
  • @MartinLiversage - "While (true)" 在 RunAsync 方法的第一行。我相信错误发生在那里,因为那是 Visual Studio 显示错误的地方(我稍后会附上屏幕截图)。
  • @AlekseyL.:感谢您的建议!你能详细说明#3吗?
  • @AlekseyL。谢谢!我将 await tx.CommitAsync() 移到了 while 循环之外并添加了一个计数器,因此它只会在计数器大于 0 并且在所有 TryRemoveAsync() 完全完成后才会提交事务。在 await deleteExpired("MyDictionaryName", cancelToken) 之后,我还添加了一个 await Task.Delay(60000)。这似乎解决了问题!

标签: c# azure-service-fabric service-fabric-stateful


【解决方案1】:

如果 Reliable Dictionary 包含多个准备过期的项目,则上述代码在事务终止后继续使用事务(在上述情况下已提交)。这会导致枚举中的断言,因为它是在它绑定到的事务终止后使用的。

我会将Reliable Collections中的推荐更新为

  • 在用于创建的事务终止(提交/中止)或处置后,请勿使用枚举。

【讨论】:

  • 谢谢!我将 await tx.CommitAsync() 移到了 while 循环之外并添加了一个计数器,因此它只会在计数器大于 0 并且在所有 TryRemoveAsync() 完全完成后才会提交事务。在 await deleteExpired("MyDictionaryName", cancelToken) 之后,我还添加了一个 await Task.Delay(60000)。这似乎解决了问题!
猜你喜欢
  • 2017-05-08
  • 2020-12-25
  • 2018-12-08
  • 1970-01-01
  • 2016-06-28
  • 2017-01-29
  • 2018-03-07
  • 2019-09-03
  • 2019-07-13
相关资源
最近更新 更多