Автоматически удалять объекты надежного словаря Service Fabric с помощью RunAsync

Я пытаюсь добавить автоматические удаления к надежным объектам словаря с истекшим сроком действия, и похоже, что мне нужно реализовать свой собственный способ в соответствии с этим: 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».

Дополнительная информация: среда выполнения обнаружила фатальную ошибку. Адрес ошибки был 0x8c46ed90 в потоке 0x1980. Код ошибки - 0x80131623. Эта ошибка может быть ошибкой в ​​CLR или в небезопасных или неподдающихся проверке частях пользовательского кода. Общие источники этой ошибки включают ошибки маршалинга пользователей для COM-взаимодействия или PInvoke, которые могут повредить стек.


person TheSugoiBoi    schedule 28.12.2016    source источник
comment
Я не вижу while (true) в вашем коде, и откуда вы знаете, что ошибка возникает в while (true), когда это очевидно фатальная ошибка в вашем процессе, а не исключение .NET с трассировкой стека, которая позволяет вам понять, какая часть вашего код, который не удался? Я не думаю, что в вашем коде есть что-то, что может вызвать подобную ошибку, поэтому я предполагаю, что ошибка не связана с опубликованным вами кодом или вы столкнулись с ошибкой в ​​Service Fabric.   -  person Martin Liversage    schedule 29.12.2016
comment
Не связано с ошибкой, но 1.CommitAsync должен быть после внутреннего цикла while (вы не можете использовать транзакцию после фиксации). 2. Добавьте задержку await Task.Delay(...) после await deleteExpired... 3. Не рекомендуется совмещать операции одного и нескольких объектов в одной транзакции.   -  person Aleksey L.    schedule 29.12.2016
comment
@MartinLiversage - пока (true) находится в первой строке метода RunAsync. Я считаю, что ошибки возникают там, потому что именно здесь Visual Studio показывает ошибку (позже я приложу снимок экрана).   -  person TheSugoiBoi    schedule 29.12.2016
comment
@AlekseyL .: Спасибо за совет! Не могли бы вы подробнее рассказать о № 3?   -  person TheSugoiBoi    schedule 29.12.2016
comment
@AlekseyL. Спасибо! Я переместил await tx.CommitAsync () за пределы цикла while и добавил счетчик, чтобы он фиксировал транзакцию только в том случае, если счетчик больше 0 и после того, как она полностью завершится со всеми TryRemoveAsync (). Я также добавил ожидание Task.Delay (60000) после ожидания deleteExpired (MyDictionaryName, cancellationToken). Похоже, это решило проблему!   -  person TheSugoiBoi    schedule 29.12.2016


Ответы (1)


Если Reliable Dictionary содержит более одного элемента, срок действия которого истекает, приведенный выше код продолжает использовать транзакцию после ее завершения (зафиксировано в приведенном выше случае). Это вызывает утверждение в перечислении, поскольку оно используется после завершения транзакции, к которой он был привязан.

Я обновлю рекомендацию в Надежные коллекции в

  • Не используйте перечисление после того, как транзакция, использованная для создания, завершена (зафиксирована / прервана) или удалена.
person Mert Coskun - MSFT    schedule 29.12.2016
comment
Спасибо! Я переместил await tx.CommitAsync () за пределы цикла while и добавил счетчик, чтобы он фиксировал транзакцию только в том случае, если счетчик больше 0 и после того, как она полностью завершится со всеми TryRemoveAsync (). Я также добавил ожидание Task.Delay (60000) после ожидания deleteExpired (MyDictionaryName, cancellationToken). Похоже, это решило проблему! - person TheSugoiBoi; 29.12.2016