Извините за поздний ответ (который вам, вероятно, больше не нужен, но все же) .
Когда мы вызываем метод GetOrAddAsync
для IReliableStateManager
, мы не получаеминтерфейс для хранения ценностей - мы фактически создаем экземпляр надежной коллекции.Это в основном означает, что тип интерфейса, который мы указываем, очень важен.
Принимая это во внимание, если мы делаем это:
Service v. 1.0
// Somewhere in RunAsync for example
await this.StateManager.GetOrAddAsync<IReliableQueue<long>>("MyCollection")
Затем выполните это в следующей версии:
Service v. 1.1
// Somewhere in RunAsync for example
await this.StateManager.GetOrAddAsync<IReliableConcurrentQueue<long>>("MyCollection")
сгенерирует исключение:
Возвращенный надежный объект типа Microsoft.ServiceFabric.Data.Collections.DistributedQueue`1 [System.Int64] не может быть преобразован в запрошенный тип Microsoft.ServiceFabric.Data.Collections.IReliableConcurrentQueue`1 [System.Int64]
, а затем:
System.ExecutionEngineException: было сгенерировано исключение типа System.ExecutionEngineException.
Это исключение выглядит как ошибка, поэтому язаполнили один .
ОБНОВЛЕНИЕ 2019.06.28
Оказалось, что появление System.ExecutionEngineException
не ошибка, носкорее недокументированное поведение метода Environment.FailFast
в сочетании с отладчиком Visual Studio.
Пожалуйста, смотрите мой комментарий к вышеуказанному вопросу.
Вот что произойдет.
Существует множество способов преодолеть это.
Вот наиболее очевидный из них:
Пример
var migrate = false; // This flag indicates whether the migration was already done.
var migrateValues = new List<long>();
var applicationFlags = await this.StateManager
.GetOrAddAsync<IReliableDictionary<string, bool>>("application-flags");
using (var transaction = this.StateManager.CreateTransaction())
{
var flag = await applicationFlags
.TryGetValueAsync(transaction, "queue-to-concurrent-queue-migration");
if (!flag.HasValue || !flag.Value)
{
var queue = await this.StateManager
.GetOrAddAsync<IReliableQueue<long>>("value-collection");
for (;;)
{
var c = await queue.TryDequeueAsync(transaction);
if (!c.HasValue)
{
break;
}
migrateValues.Add(c.Value);
}
migrate = true;
}
}
if (migrate)
{
await this.StateManager.RemoveAsync("value-collection");
using (var transaction = this.StateManager.CreateTransaction())
{
var concurrentQueue = await this.StateManager
.GetOrAddAsync<IReliableConcurrentQueue<long>>("value-collection");
foreach (var i in migrateValues)
{
await concurrentQueue.EnqueueAsync(transaction, i);
}
await applicationFlags.AddOrUpdateAsync(
transaction,
"queue-to-concurrent-queue-migration",
true,
(s, b) => true);
}
await transaction.CommitAsync();
}
Пожалуйстаобратите внимание, что этот код является лишь иллюстративным примером и должен быть надлежащим образом протестирован, прежде чем применять его в реальных приложениях.