Beispiel #1
0
        public async Task ProcessDependencyUpdateErrorsAsync()
        {
            if (_options.IsEnabled)
            {
                IReliableDictionary <string, DateTimeOffset> checkpointEvaluator =
                    await _stateManager.GetOrAddAsync <IReliableDictionary <string, DateTimeOffset> >("checkpointEvaluator");

                try
                {
                    DateTimeOffset checkpoint;
                    using (ITransaction tx = _stateManager.CreateTransaction())
                    {
                        checkpoint = await checkpointEvaluator.GetOrAddAsync(
                            tx,
                            "checkpointEvaluator",
                            DateTimeOffset.UtcNow
                            );

                        await tx.CommitAsync();
                    }
                    await CheckForErrorsInUpdateHistoryTablesAsync(
                        checkpoint,
                        _options.GithubUrl,
                        checkpointEvaluator);
                }
                catch (TimeoutException exe)
                {
                    _logger.LogError(exe, "Unable to connect to reliable services.");
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Unable to create a github issue.");
                }
            }
        }
Beispiel #2
0
        public async Task <IActionResult> Get(string id)
        {
            try
            {
                var dictionary = await _stateManager.GetOrAddAsync <IReliableDictionary <string, BookingAggregates> >(ValuesDictionaryName);

                using (ITransaction tx = _stateManager.CreateTransaction())
                {
                    var result = await dictionary.TryGetValueAsync(tx, id);

                    if (result.HasValue)
                    {
                        return(Ok(result.Value));
                    }

                    return(NotFound());
                }
            }
            catch (FabricNotPrimaryException)
            {
                return(new ContentResult {
                    StatusCode = 410, Content = "The primary replica has moved. Please re-resolve the service."
                });
            }
            catch (FabricException)
            {
                return(new ContentResult {
                    StatusCode = 503, Content = "The service was unable to process the request. Please try again."
                });
            }
        }
Beispiel #3
0
        public ActionResult <Model.DeviceStatus> Get(string id)
        {
            var status = new Model.DeviceStatus();

            if (string.IsNullOrWhiteSpace(id))
            {
                return(status);
            }

            var devStatusCollection =
                stateManager.GetOrAddAsync <IReliableDictionary <string, Model.DeviceStatus> >(
                    ReliableObjectNames.DeviceStatusDictionary)
                .GetAwaiter()
                .GetResult();

            using (var txn = stateManager.CreateTransaction())
            {
                var devData = devStatusCollection.TryGetValueAsync(txn, id).GetAwaiter().GetResult();
                if (devData.HasValue)
                {
                    status = devData.Value;
                }
                else
                {
                    status.Id     = id;
                    status.Status = "Unknown";
                }
            }

            return(status);
        }
        private async Task <IReliableDictionary <string, byte[]> > OpenCollectionAsync()
        {
            IReliableDictionary <string, byte[]> collection =
                await _stateManager.GetOrAddAsync <IReliableDictionary <string, byte[]> >(_collectionName).ConfigureAwait(false);

            return(collection);
        }
        public override async Task OnConnectedAsync()
        {
            await base.OnConnectedAsync();

            if (!Context.User.IsInRole(Strings.System))
            {
                var connections = await _reliableStateManager.GetOrAddAsync <IReliableDictionary <string, string> >("Connections");

                using (ITransaction tx = _reliableStateManager.CreateTransaction()) {
                    var success = await connections.TryAddAsync(tx, Context.UserIdentifier, Context.ConnectionId);

                    await tx.CommitAsync();

                    if (!success)
                    {
                        Context.Abort();
                        return;
                    }

                    ConnectedUserIds.Add(Context.UserIdentifier);

                    await Groups.AddToGroupAsync(Context.ConnectionId, TenantId);

                    await Clients.Group(TenantId).ShowUsersOnLine((await GetConnectionsDictionary(connections)).Where(x => x.Key.StartsWith(TenantId)).Count());

                    await Clients.Caller.ConnectionId(Context.ConnectionId);

                    await Clients.Group(Strings.System).ConnectionsChanged(await GetConnectionsDictionary(connections));
                }
            }
            else
            {
                await Groups.AddToGroupAsync(Context.ConnectionId, Strings.System);
            }
        }
Beispiel #6
0
        public virtual async Task <ConditionalValue <T> > Dequeue(ITransaction scope, CancellationToken cancellationToken)
        {
            var specDataQueue = await _stateManager.GetOrAddAsync <IReliableQueue <T> >(_queueName);

            try
            {
                await _signal.WaitAsync(cancellationToken);


                var result = await specDataQueue.TryDequeueAsync(scope);

                var countDiff = await GetCountDiff(scope);

                if (countDiff > 0)
                {
                    _signal.Release(countDiff);
                }


                return(result);
            }
            catch (FabricNotReadableException ex)
            {
                throw;
            }
        }
Beispiel #7
0
        public async Task <IHttpActionResult> Put([FromBody] CartItem cartItem)
        {
            var cartDict = await stateManager
                           .GetOrAddAsync <IReliableDictionary <int, IEnumerable <CartItem> > >("cartDictionary");

            using (ITransaction tx = stateManager.CreateTransaction())
            {
                ConditionalValue <IEnumerable <CartItem> > result = await cartDict
                                                                    .TryGetValueAsync(tx, cartItem.CustomerId);

                var newList = new List <CartItem> {
                    cartItem
                };

                if (result.HasValue)
                {
                    IEnumerable <CartItem> newCart = result.Value.Concat(newList);
                    await cartDict.SetAsync(tx, cartItem.CustomerId, newCart);
                }
                else
                {
                    await cartDict.AddAsync(tx, cartItem.CustomerId, newList);
                }

                await tx.CommitAsync();
            }

            return(Ok());
        }
Beispiel #8
0
        public static async Task <DataStore <TId, TModel> > AddDocumentStore <TId, TModel>(
            this IReliableStateManager stateManager, Expression <Func <TModel, string> >[] indexedMembers, string name = null)
            where TId : IComparable <TId>, IEquatable <TId>
            where TModel : IDto <TId>
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                name = typeof(TModel).Name;
            }

            var wrappedReliableDictionary = await stateManager.GetOrAddAsync <IReliableDictionary <TId, TModel> >(name);

            Func <ITransaction> transactionBuilder = stateManager.CreateTransaction;

            async Task <IAsyncKeyValueStore <FieldValue, HashSet <TId> > > BuildFieldIndexPersistence(string memberName)
            {
                var dictionary = await stateManager.GetOrAddAsync <IReliableDictionary <FieldValue, HashSet <TId> > >($"{name}_{memberName}");

                return(new ServiceFabAsyncKeyValueStore <FieldValue, HashSet <TId> >(dictionary, transactionBuilder));
            }

            var store = await DataStore <TId, TModel> .Build(
                () => new ServiceFabAsyncKeyValueStore <TId, TModel>(wrappedReliableDictionary, transactionBuilder),
                BuildFieldIndexPersistence,
                indexedMembers);

            return(store);
        }
        public async Task <IActionResult> End([FromBody] ServiceMessage message)
        {
            try
            {
                message.StampFive.Visited = true;
                message.StampFive.TimeNow = DateTime.UtcNow;

                var storage = await _manager.GetOrAddAsync <IReliableDictionary <string, ServiceMessage> >("storage");

                using (var tx = _manager.CreateTransaction())
                {
                    await storage.AddOrUpdateAsync(tx, message.MessageId, message, (k, m) =>
                    {
                        //m.StampOne = message.StampOne;
                        //m.StampTwo = message.StampTwo;
                        //m.StampThree = message.StampThree;
                        //m.StampFour = message.StampFour;

                        //m.StampFive.Visited = true;
                        //m.StampFive.TimeNow = DateTime.UtcNow;
                        //return m;
                        return(message);
                    });

                    await tx.CommitAsync();
                }

                return(Ok());
            }
            catch (Exception e)
            {
                return(BadRequest(e.Message));
            }
        }
Beispiel #10
0
        public async Task <HttpResponseMessage> GetFullTelemetryFrame(int id)
        {
            if (id == 0)
            {
                return(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "No Data"));
            }


            var dataCollection = await _reliableStateManager.GetOrAddAsync <IReliableDictionary <int, Telemetry> >(String.Format("VehicleId-{0}", id));

            using (ITransaction transaction = _reliableStateManager.CreateTransaction())
            {
                ConditionalResult <Telemetry> result = await dataCollection.TryGetValueAsync(transaction, 0);

                if (result.HasValue)
                {
                    HttpResponseMessage httpResponseMessage = Request.CreateResponse <Telemetry>(result.Value);
                    httpResponseMessage.StatusCode = HttpStatusCode.Found;
                    return(httpResponseMessage);
                }
                else
                {
                    HttpResponseMessage httpResponseMessage = Request.CreateResponse();
                    httpResponseMessage.StatusCode = HttpStatusCode.NotFound;
                    return(httpResponseMessage);
                }
            }
        }
        public async Task <IEnumerable <string> > Get()
        {
            var result = new List <string>();

            try
            {
                var dict = await stateManager.GetOrAddAsync <IReliableDictionary <string, VehicleRegistration> >(LicensePlates);

                using (ITransaction tx = stateManager.CreateTransaction())
                {
                    var enu = await dict.CreateEnumerableAsync(tx);

                    using (Microsoft.ServiceFabric.Data.IAsyncEnumerator <KeyValuePair <string, VehicleRegistration> > enumerator = enu.GetAsyncEnumerator())
                    {
                        while (await enumerator.MoveNextAsync(CancellationToken.None))
                        {
                            var value = enumerator.Current;
                            result.Add(value.Key);
                        }
                    }
                }
            }
            catch (TimeoutException)
            {
                return(null);
            }

            return(result);
        }
        public async Task Consume(ConsumeContext <IAddWord> context)
        {
            var wordCountDictionary =
                await _stateManager.GetOrAddAsync <IReliableDictionary <string, long> >("wordCountDictionary")
                .ConfigureAwait(false);

            var statsDictionary =
                await _stateManager.GetOrAddAsync <IReliableDictionary <string, long> >("statsDictionary")
                .ConfigureAwait(false);

            using (var tx = _stateManager.CreateTransaction())
            {
                var word = context.Message.Word;

                await wordCountDictionary.AddOrUpdateAsync(
                    tx,
                    word,
                    1,
                    (key, oldValue) => oldValue + 1).ConfigureAwait(false);

                await statsDictionary.AddOrUpdateAsync(
                    tx,
                    "Number of Words Processed",
                    1,
                    (key, oldValue) => oldValue + 1).ConfigureAwait(false);

                await tx.CommitAsync().ConfigureAwait(false);
            }
        }
Beispiel #13
0
        public async Task <IActionResult> Post(string distName, [FromBody] DistrictReport distReport)
        {
            try
            {
                IReliableDictionary <string, DistrictReport> distReports =
                    await stateManager.GetOrAddAsync <IReliableDictionary <string, DistrictReport> >(CityReports);

                using (ITransaction tx = this.stateManager.CreateTransaction())
                {
                    await distReports.SetAsync(tx, distName, distReport);

                    await tx.CommitAsync();
                }

                return(this.Ok());
            }
            catch (FabricNotPrimaryException ex)
            {
                return(new ContentResult {
                    StatusCode = 410, Content = "The primary replica has moved. Please re-resolve the service."
                });
            }
            catch (FabricException ex)
            {
                return(new ContentResult {
                    StatusCode = 503, Content = "The service was unable to process the request. Please try again."
                });
            }
        }
Beispiel #14
0
        /// <summary>
        /// Get all things name.
        /// </summary>
        /// <returns></returns>
        public async Task <IEnumerable <Thing> > GetAllThings()
        {
            var products = await _stateManager.GetOrAddAsync <IReliableDictionary <string, Guid> >("thingsIds");

            var result = new List <Thing>();

            using (var transaction = _stateManager.CreateTransaction())
            {
                var allProducts = await products.CreateEnumerableAsync(transaction, EnumerationMode.Unordered);

                using (var enumerator = allProducts.GetAsyncEnumerator())
                {
                    while (await enumerator.MoveNextAsync(CancellationToken.None))
                    {
                        var(key, value) = enumerator.Current;
                        var actorService = GetActorInstance(value);
                        result.Add(new Thing()
                        {
                            Id   = value,
                            Name = await actorService.GetThingsName(key)
                        });
                    }
                }
            }

            return(result);
        }
        public override async Task OnConnected()
        {
            var map = await StateManager.GetOrAddAsync <SignalrState <Guid, List <string> > >("UserConnectionMap");

            using (var tx = StateManager.CreateTransaction())
            {
                var connections = await map.TryGetValueAsync(tx, _testUserId);

                if (ConnectionAlreadySaved(Context.ConnectionId, ref connections))
                {
                    return;
                }

                if (UserHasAnyConnections(connections.Value))
                {
                    var list = connections.Value.ToList();
                    list.Add(Context.ConnectionId);
                    await map.SetAsync(tx, _testUserId, list);

                    await tx.CommitAsync();
                }
                else
                {
                    await map.SetAsync(tx, _testUserId, new List <string> {
                        Context.ConnectionId
                    });

                    await tx.CommitAsync();
                }
            }

            await base.OnConnected();
        }
        private async Task <IEnumerable <QueueMessage> > ReceiveMessagesAsync(int count)
        {
            IReliableQueue <byte[]> collection = await _stateManager.GetOrAddAsync <IReliableQueue <byte[]> >(_queueName);

            var result = new List <QueueMessage>();

            using (var tx = new ServiceFabricTransaction(_stateManager, null))
            {
                while (result.Count < count)
                {
                    ConditionalValue <byte[]> message = await collection.TryDequeueAsync(tx.Tx);

                    if (message.HasValue)
                    {
                        QueueMessage qm = QueueMessage.FromByteArray(message.Value);

                        result.Add(qm);
                    }
                    else
                    {
                        break;
                    }
                }

                await tx.CommitAsync();
            }

            return(result.Count == 0 ? null : result);
        }
        public async Task <IActionResult> Post([FromQuery] string dictionaryName, [FromQuery] string keyRecord, [FromBody] dynamic dataObject)
        {
            try
            {
                var dictionary = await _stateManager.GetOrAddAsync <IReliableDictionary <string, string> >(dictionaryName);

                using (ITransaction tx = _stateManager.CreateTransaction())
                {
                    string datos = JsonConvert.SerializeObject(dataObject);
                    //await dictionary.SetAsync(tx, keyRecord, datos);
                    await dictionary.AddOrUpdateAsync(tx, keyRecord, datos, (key, value) => datos);

                    await tx.CommitAsync();
                }

                return(Ok());
            }
            catch (FabricNotPrimaryException)
            {
                return(new ContentResult {
                    StatusCode = 410, Content = "The primary replica has moved. Please re-resolve the service."
                });
            }
            catch (FabricException)
            {
                return(new ContentResult {
                    StatusCode = 503, Content = "The service was unable to process the request. Please try again."
                });
            }
        }
Beispiel #18
0
        public static async Task RegisterOutboxStorage(this IReliableStateManager stateManager, OutboxStorage storage, CancellationToken cancellationToken = default)
        {
            storage.Outbox = await stateManager.GetOrAddAsync <IReliableDictionary <string, StoredOutboxMessage> >("outbox").ConfigureAwait(false);

            storage.CleanupOld = await stateManager.GetOrAddAsync <IReliableQueue <CleanupStoredOutboxCommand> >("outboxCleanup").ConfigureAwait(false);

            storage.Cleanup = await stateManager.GetOrAddAsync <IReliableConcurrentQueue <CleanupStoredOutboxCommand> >("outboxCleanupConcurrent").ConfigureAwait(false);
        }
Beispiel #19
0
        private static async Task RegisterChaosEventAndUpdateChaosStatusPrivateAsync(
            this IReliableStateManager stateManager,
            ChaosEvent chaosEvent,
            ChaosStatus currentStatus,
            Action postAction,
            CancellationToken cancellationToken)
        {
            var eventsDictionary = await stateManager.GetOrAddAsync <IReliableDictionary <long, byte[]> >(FASConstants.ChaosEventsDictionaryName).ConfigureAwait(false);

            var lastEventKeyDictionary = await stateManager.GetOrAddAsync <IReliableDictionary <string, byte[]> >(FASConstants.ChaosLastEventKeyDictionaryName).ConfigureAwait(false);

            var statusDictionary = await stateManager.GetOrAddAsync <IReliableDictionary <string, byte[]> >(FASConstants.ChaosStatusDictionaryName).ConfigureAwait(false);

            using (ITransaction tx = stateManager.CreateTransaction())
            {
                long eventKey = chaosEvent.TimeStampUtc.Ticks;
                if (await eventsDictionary.ContainsKeyAsync(tx, eventKey, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false))
                {
                    ++eventKey;
                    chaosEvent.TimeStampUtc = chaosEvent.TimeStampUtc.AddTicks(1);
                }

                byte[] chaosEventInBytes = chaosEvent.ToBytes();

                TestabilityTrace.TraceSource.WriteInfo(TraceType, "RegisterChaosEventAndUpdateChaosStatusPrivateAsync attempting to add event == {0} with key {1}.", chaosEvent, eventKey);

                await eventsDictionary.AddOrUpdateAsync(tx, eventKey, chaosEventInBytes, (k, v) => chaosEventInBytes, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false);

                await lastEventKeyDictionary.UpdateLastEventKeyAsync(tx, chaosEvent.TimeStampUtc.Ticks, cancellationToken).ConfigureAwait(false);

                // Update status
                byte[] statusInBytes = BitConverter.GetBytes((int)currentStatus);

                if (await statusDictionary.ContainsKeyAsync(tx, FASConstants.ChaosStatusKeyName, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false))
                {
                    TestabilityTrace.TraceSource.WriteInfo(TraceType, "RegisterChaosEventAndUpdateChaosStatusPrivateAsync attempting to update status == {0} with key {1}.", currentStatus, FASConstants.ChaosStatusKeyName);

                    await statusDictionary.SetAsync(tx, FASConstants.ChaosStatusKeyName, statusInBytes, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    TestabilityTrace.TraceSource.WriteInfo(TraceType, "RegisterChaosEventAndUpdateChaosStatusPrivateAsync attempting to add status == {0} with key {1}.", currentStatus, FASConstants.ChaosStatusKeyName);

                    await statusDictionary.AddAsync(tx, FASConstants.ChaosStatusKeyName, statusInBytes, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false);
                }

                if (postAction != null)
                {
                    postAction();
                }

                TestabilityTrace.TraceSource.WriteInfo(TraceType, "RegisterChaosEventAndUpdateChaosStatusPrivateAsync stored event == {0} and status {1}.", chaosEvent, currentStatus);

                await tx.CommitAsync().ConfigureAwait(false);
            }
        }
Beispiel #20
0
        private static async Task <bool> ChaosWasRunningAsyncPrivate(
            IReliableStateManager stateManager,
            CancellationToken cancellationToken)
        {
            // If Chaos was previously stopped, no need to do anything, return immediately; otherwise move on...
            bool shouldReturn = false;

            var lastEventKeyDict = await stateManager.GetOrAddAsync <IReliableDictionary <string, byte[]> >(FASConstants.ChaosLastEventKeyDictionaryName).ConfigureAwait(false);

            using (var tx = stateManager.CreateTransaction())
            {
                if (await lastEventKeyDict.ContainsKeyAsync(tx, FASConstants.ChaosLastEventKeyName, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false))
                {
                    var lastEventKey = await lastEventKeyDict.TryGetValueAsync(tx, FASConstants.ChaosLastEventKeyName, LockMode.Update, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false);

                    if (lastEventKey.HasValue)
                    {
                        var lastKey    = BitConverter.ToInt64(lastEventKey.Value, 0);
                        var eventsDict = await stateManager.GetOrAddAsync <IReliableDictionary <long, byte[]> >(FASConstants.ChaosEventsDictionaryName).ConfigureAwait(false);

                        var lastEventResult = await eventsDict.TryGetValueAsync(tx, lastKey, FASConstants.ReliableDictionaryTimeout, cancellationToken).ConfigureAwait(false);

                        if (lastEventResult.HasValue)
                        {
                            var lastEvent = ByteSerializationHelper.GetEventFromBytes(lastEventResult.Value);

                            // Starts only if the lastevent was a StoppedEvent, because if it was not stopped, it should already be
                            // running; if the user need to change the params, he need to stop it first, then start with the
                            // new parameter
                            bool wasStopped = lastEvent is StoppedEvent;
                            if (wasStopped)
                            {
                                shouldReturn = true;
                            }
                        }
                    }
                    else
                    {
                        shouldReturn = true;
                    }
                }
                else
                {
                    shouldReturn = true;
                }

                await tx.CommitAsync().ConfigureAwait(false);

                if (shouldReturn)
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #21
0
        public async Task AddAProduct(Product _product)
        {
            var products = await stateManager.GetOrAddAsync <IReliableDictionary <Guid, Product> >("myproducts");

            using (var tx = stateManager.CreateTransaction()) {
                await products.AddOrUpdateAsync(tx, _product.ProductID, _product, (id, value) => _product);

                await tx.CommitAsync();
            }
        }
        public async Task AddCustomer(CustomerEntity cust)
        {
            var customer = await _manager.GetOrAddAsync <IReliableDictionary <int, CustomerEntity> >("CustomerStore");

            using (var tx = _manager.CreateTransaction()) {
                var result = await customer.AddOrUpdateAsync(tx, cust.CustomerId, cust, (id, val) => cust);

                await tx.CommitAsync();
            }
        }
        public async Task AddCustomer(Users customer)
        {
            var customerDictionary = await _stateManager.GetOrAddAsync <IReliableDictionary <Guid, Users> >("myCustomers");

            using (var tx = _stateManager.CreateTransaction()) {
                await customerDictionary.AddOrUpdateAsync(tx, customer.CustomerId, customer, (id, key) => customer);

                await tx.CommitAsync();
            }
        }
        public async Task AddProduct(Product product)
        {
            var offerlist = await _reliableStateManager.GetOrAddAsync <IReliableDictionary <int, Product> >("offers");

            using (var tx = _reliableStateManager.CreateTransaction())
            {
                await offerlist.AddOrUpdateAsync(tx, product.ProductId, product, (id, value) => product);

                await tx.CommitAsync();
            }
        }
Beispiel #25
0
        public async Task AddToDoList(ToDoListContainer toDoList)
        {
            var result = await _stateManager.GetOrAddAsync <IReliableDictionary <Guid, ToDoListContainer> >("ToDoListRepo");

            using (var tx = _stateManager.CreateTransaction())
            {
                await result.AddOrUpdateAsync(tx, toDoList.ID, toDoList, (id, value) => toDoList);

                await tx.CommitAsync();
            }
        }
        public async Task <string> GetOffset(string partitionId)
        {
            IReliableDictionary <string, string> myDictionary = await _stateManager.GetOrAddAsync <IReliableDictionary <string, string> >("offsetDictionary");

            ConditionalValue <string> result = await myDictionary.TryGetValueAsync(_transaction, GetPartitionOffsetKey(partitionId));

            ServiceEventSource.Current.Message("Current Counter Value: {0}",
                                               result.HasValue ? result.Value : "Value does not exist.");

            return(result.HasValue ? result.Value : string.Empty);
        }
        public async Task AddProductAsync(Product newProduct)
        {
            var products = await _stateManager.GetOrAddAsync <IReliableDictionary <Guid, Product> >("products");

            using (var transaction = _stateManager.CreateTransaction())
            {
                await products.AddOrUpdateAsync(transaction, newProduct.Id, newProduct, (id, value) => newProduct);

                await transaction.CommitAsync();
            }
        }
        public async Task AddProduct(Product product)
        {
            var productStorage = await _stateManager.GetOrAddAsync <IReliableDictionary <Guid, Product> >("products");

            using (var tx = _stateManager.CreateTransaction())
            {
                await productStorage.AddOrUpdateAsync(tx, product.ProductID, product, (id, value) => product);

                await tx.CommitAsync();
            }
        }
        public async Task AddDevice(Device device)
        {
            var devices = await stateManager.GetOrAddAsync <IReliableDictionary <Guid, Device> >("devices");

            using (var trx = stateManager.CreateTransaction())
            {
                await devices.AddOrUpdateAsync(trx, device.Id, device, (id, value) => device);

                await trx.CommitAsync();
            }
        }
        public async Task SaveAsync(T entity, string id)
        {
            using (var tx = _stateManager.CreateTransaction())
            {
                var collection = await _stateManager.GetOrAddAsync <IReliableDictionary <string, T> >(_collectionName);

                await collection.AddOrUpdateAsync(tx, id, x => entity, (s, arg2) => entity);

                await tx.CommitAsync();
            }
        }