public async Task <bool> TryUpdateAsync(ITransaction tx, TKey key, TValue newValue, TValue comparisonValue) { if (reliableDictionary == null) { await InitializeReliableDictionary(); } return(await reliableDictionary.TryUpdateAsync(tx, key, newValue, comparisonValue)); }
private async Task PersistChanges(Order order, OrderSnapshot initial, IReliableDictionary <Guid, OrderSnapshot> dictionary, ITransaction transaction) { var updated = await dictionary.TryUpdateAsync(transaction, order.Id, order.GetSnapshot(), initial); if (updated && order.IsClosed()) { await dictionary.TryRemoveAsync(transaction, order.Id); } }
private async Task ExecuteUpdateUserTransactionalAsync(ITransaction tx, User user, IReliableDictionary <string, User> users, CancellationToken cancellationToken) { var current = await users.TryGetValueAsync(tx, user.Id, LockMode.Update); if (current.HasValue) { await users.TryUpdateAsync(tx, user.Id, user, current.Value, TimeSpan.FromSeconds(15), cancellationToken); } else { throw new ApplicationException($"Cannot update non existent user '{user.Id}'"); } }
public async Task Update(string id, T entity) { var oldEntityt = (await _aggreateStorage.TryGetValueAsync(_transaction, id)).Value; var storableEntity = _mapper.MapToStorable(entity); var succeed = await _aggreateStorage.TryUpdateAsync(_transaction, entity.Id, storableEntity, oldEntityt); if (!succeed) { throw new Exception($"Something went wrong when trying to update the entity {id}"); } }
private async Task <bool> UpdateLastAccessedAsync(string key, CacheEntry storedEntry, IReliableDictionary <string, CacheEntry> dictionary, TimeSpan timeout, CancellationToken cancellationToken) { var newEntry = (CacheEntry)storedEntry.Clone(); newEntry.LastAccessed = DateTimeOffset.UtcNow; using (var transaction = _stateManager.CreateTransaction()) { var result = await dictionary.TryUpdateAsync(transaction, key, newEntry, storedEntry, timeout, cancellationToken); await transaction.CommitAsync(); return(result); } }
/// <summary> /// Registers the configuration. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> public async Task <bool> RegisterConfiguration(ConsumerConfigureRequestModel request) { IReliableDictionary <string, ConsumerConfiguresState> dictionary = await this.StateManager.GetOrAddAsync <IReliableDictionary <string, ConsumerConfiguresState> >(DictionaryKey); using (ITransaction tx = this.StateManager.CreateTransaction()) { ConditionalValue <ConsumerConfiguresState> result = await dictionary.TryGetValueAsync(tx, ConfigureKey); bool isSuc; if (result.HasValue) { int count = result.Value.Configures.Count(x => x.Action.Equals(request.Action) && x.ServiceName.Equals(request.ServiceName) && x.DictionaryKey.Equals(request.DictionaryKey)); if (count > 0) { return(false); } ConsumerConfiguresState configure = result.Value; configure.Configures.Add(new ConsumerConfigureInfo { Action = request.Action, Address = request.Address, ServiceName = request.ServiceName, DictionaryKey = request.DictionaryKey }); isSuc = await dictionary.TryUpdateAsync(tx, ConfigureKey, configure, result.Value); return(isSuc); } ConsumerConfiguresState state = new ConsumerConfiguresState { Configures = new List <ConsumerConfigureInfo> { new ConsumerConfigureInfo { Action = request.Action, Address = request.Address, ServiceName = request.ServiceName, DictionaryKey = request.DictionaryKey } } }; isSuc = await dictionary.TryAddAsync(tx, ConfigureKey, state); await tx.CommitAsync(); return(isSuc); } }
public async Task <bool> AddOrUpdateAsync(Person person) { using (var ctx = this.StateManager.CreateTransaction()) { var personId = person.Id; var currentPerson = (Person)null; if (await _personDictionary.ContainsKeyAsync(ctx, personId)) { var personValue = await _personDictionary.TryGetValueAsync(ctx, personId); if (personValue.HasValue) { currentPerson = personValue.Value; } } if (currentPerson == null) { await _personDictionary.AddAsync(ctx, person.Id, person); if (!String.IsNullOrWhiteSpace(person.EmailAddress)) { await _emailLookupDictionary.AddAsync(ctx, person.EmailAddress, person.Id); } if (!String.IsNullOrWhiteSpace(person.TwitterHandle)) { await _twitterLookupDictionary.AddAsync(ctx, person.TwitterHandle, person.Id); } await ctx.CommitAsync(); return(true); } else { if (await _personDictionary.TryUpdateAsync(ctx, person.Id, person, currentPerson)) { await ctx.CommitAsync(); return(true); } } } return(false); }
public async Task <IActionResult> Put(int characterId) { try { IReliableDictionary <int, Character> characterDictionary = await _stateManager.GetOrAddAsync <IReliableDictionary <int, Character> >(CharactersName); using (ITransaction tx = _stateManager.CreateTransaction()) { var characterConditionalValue = await characterDictionary.TryGetValueAsync(tx, characterId); if (!characterConditionalValue.HasValue) { return(new BadRequestResult()); } var character = characterConditionalValue.Value; // this is invalid, it will not update the replicas // character.Votes++; var cloned = (Character)character.Clone(); cloned.Votes += 2; await characterDictionary.TryUpdateAsync(tx, characterId, cloned, character); // alternative //await characterDictionary.AddOrUpdateAsync(tx, characterId, character, (value, oldvalue) => //{ // oldvalue.Votes++; // return oldvalue; //}); await tx.CommitAsync(); } return(new OkResult()); } catch { return(new BadRequestResult()); } }
private async Task <bool> ExecuteUpdateUserAsync(User user, IReliableDictionary <string, User> users, CancellationToken cancellationToken) { bool result; using (var tx = this.StateManager.CreateTransaction()) { var current = await users.TryGetValueAsync(tx, user.Id, LockMode.Update); if (current.HasValue) { result = await users.TryUpdateAsync(tx, user.Id, user, current.Value, TimeSpan.FromSeconds(15), cancellationToken); await tx.CommitAsync(); MetricsLog?.UserUpdated(user); } else { throw new ApplicationException($"Cannot update non existent user '{user.Id}'"); } } return(result); }
/// <summary> /// Performs a HealthCheck for a scheduled item. /// </summary> /// <param name="item">WatchdogScheduledItem instance.</param> internal async Task PerformItemHealthCheckAsync(WatchdogScheduledItem item) { // Get the health check dictionaries. IReliableDictionary <string, HealthCheck> dict = await this.GetHealthCheckDictionaryAsync(); IReliableDictionary <long, WatchdogScheduledItem> scheduleDict = await this.GetHealthCheckScheduleDictionaryAsync(); // Create a transaction. using (ITransaction tx = this._service.StateManager.CreateTransaction()) { // Attempt to get the HealthCheck instance for the key. If not return. ConditionalValue <HealthCheck> cv = await dict.TryGetValueAsync(tx, item.Key, LockMode.Update); if (cv.HasValue) { HealthCheck hc = cv.Value; try { // Find the partition information that matches the partition identifier. // If the partition isn't found, remove the health check item. Partition partition = await this.FindMatchingPartitionAsync(hc.Partition); if (null == partition) { await dict.TryRemoveAsync(tx, hc.Key, this._timeout, this._token); } else { // Execute the check and evaluate the results returned in the new HealthCheck instance. hc = await this.ExecuteHealthCheckAsync(hc, partition); // Update the value of the HealthCheck to store the results of the test. await dict.TryUpdateAsync(tx, item.Key, hc, cv.Value); // Remove the current scheduled item. await scheduleDict.TryRemoveAsync(tx, item.ExecutionTicks); // Add the new scheduled item. WatchdogScheduledItem newItem = new WatchdogScheduledItem(hc.LastAttempt.Add(hc.Frequency), hc.Key); await(scheduleDict.TryAddAsync(tx, newItem.ExecutionTicks, newItem)); } // Commit the transaction. await tx.CommitAsync(); } catch (TimeoutException ex) { ServiceEventSource.Current.ServiceMessage(this._service.Context, ex.Message); } catch (FabricNotPrimaryException ex) { ServiceEventSource.Current.ServiceMessage(this._service.Context, ex.Message); return; } catch (Exception ex) { ServiceEventSource.Current.ServiceMessage(this._service.Context, ex.Message); throw; } } } }
public async Task <string> OrchestrateWorker(WorkerDescription workerDescription) { if (_processorDictionary == null) { this._processorDictionary = this.StateManager .GetOrAddAsync <IReliableDictionary <string, ProcessorInformation> >("orchestrator.ProcessorDictionary").Result; } ServiceEventSource.Current.ServiceMessage(this.Context, $"Orchestrate worker called for {workerDescription.Identifier}"); var address = String.Empty; using (var tx = this.StateManager.CreateTransaction()) { ConditionalValue <ProcessorInformation> result = new ConditionalValue <ProcessorInformation>(false, null); int retryAttempt = 0; getProcessorInfo: try { result = await _processorDictionary.TryGetValueAsync(tx, workerDescription.Identifier); } catch (TimeoutException) { // see below for explanation if (retryAttempt++ <= 5) { goto getProcessorInfo; } else { throw; } } if (result.HasValue) { var info = result.Value; retryAttempt = 0; // reset // when running on "slow" machines, if the incoming data is bad and incorrectly partitoned // we will run into time-outs, therefore it is wise to retry the operation, but we'll limit // it to 5 retry attempts updateRetry: try { await _processorDictionary.TryUpdateAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = info.Address, TicksLastUpdated = DateTime.UtcNow.Ticks }, info); await tx.CommitAsync(); } catch (TimeoutException) { retryAttempt++; if (retryAttempt >= 5) { throw; } await Task.Delay(100); goto updateRetry; } address = info.Address; } else { // spin up the new service here ServiceEventSource.Current.ServiceMessage(this.Context, $"Creating processor for {workerDescription.Identifier}"); var appName = Context.CodePackageActivationContext.ApplicationName; var svcName = $"{appName}/{Names.ProcessorSuffix}/{workerDescription.Identifier}"; address = svcName; try { await _fabricClient.ServiceManager.CreateServiceAsync(new StatefulServiceDescription() { HasPersistedState = true, PartitionSchemeDescription = new UniformInt64RangePartitionSchemeDescription(1), ServiceTypeName = Names.ProcessorTypeName, ApplicationName = new System.Uri(appName), ServiceName = new System.Uri(svcName) }); ServiceEventSource.Current.ServiceMessage(this.Context, $"Processor for {workerDescription.Identifier} running on {svcName}"); retryAttempt = 0; svcToDictionaryAdd: try { await _processorDictionary.AddAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = svcName, TicksLastUpdated = DateTime.UtcNow.Ticks }); await tx.CommitAsync(); } catch (TimeoutException) { retryAttempt++; if (retryAttempt >= 5) { throw; } await Task.Delay(100); // see above for explanation goto svcToDictionaryAdd; } } catch (FabricElementAlreadyExistsException) { // this is a weird case, that happens if the same ID was sent to multiple ServiceEventSource.Current.ServiceMessage(this.Context, $"Processor already existed for {workerDescription.Identifier} on {svcName}"); tx.Abort(); } } } return(address); }
private async Task PeriodicInventoryCheck(CancellationToken cancellationToken) { IReliableDictionary <InventoryItemId, InventoryItem> inventoryItems = await this.stateManager.GetOrAddAsync <IReliableDictionary <InventoryItemId, InventoryItem> >(InventoryItemDictionaryName); if (this.storageType == StorageTypes.Azure) { await this.InitializeAsync(cancellationToken); } while (!cancellationToken.IsCancellationRequested) { ServiceEventSource.Current.ServiceMessage(this, "Checking inventory stock for {0} items.", await inventoryItems.GetCountAsync()); foreach (InventoryItem item in inventoryItems.Select(x => x.Value)) { cancellationToken.ThrowIfCancellationRequested(); try { //Check if stock is below restockThreshold and if the item is not already on reorder if ((item.AvailableStock <= item.RestockThreshold) && !item.OnReorder) { ServiceUriBuilder builder = new ServiceUriBuilder(RestockRequestManagerServiceName); IRestockRequestManager restockRequestManagerClient = ServiceProxy.Create <IRestockRequestManager>(0, builder.ToUri()); // we reduce the quantity passed in to RestockRequest to ensure we don't overorder RestockRequest newRequest = new RestockRequest(item.Id, (item.MaxStockThreshold - item.AvailableStock)); InventoryItem updatedItem = new InventoryItem( item.Description, item.Price, item.AvailableStock, item.RestockThreshold, item.MaxStockThreshold, item.Id, true); // TODO: this call needs to be idempotent in case we fail to update the InventoryItem after this completes. await restockRequestManagerClient.AddRestockRequestAsync(newRequest); // Write operations take an exclusive lock on an item, which means we can't do anything else with that item while the transaction is open. // If something blocks before the transaction is committed, the open transaction on the item will prevent all operations on it, including reads. // Once the transaction commits, the lock is released and other operations on the item can proceed. // Operations on the transaction all have timeouts to prevent deadlocking an item, // but we should do as little work inside the transaction as possible that is not related to the transaction itself. using (ITransaction tx = this.stateManager.CreateTransaction()) { await inventoryItems.TryUpdateAsync(tx, item.Id, updatedItem, item); await tx.CommitAsync(); } ServiceEventSource.Current.ServiceMessage( this, "Restock order placed. Item ID: {0}. Quantity: {1}", newRequest.ItemId, newRequest.Quantity); } } catch (Exception e) { ServiceEventSource.Current.ServiceMessage(this, "Failed to place restock order for item {0}. {1}", item.Id, e.ToString()); } if (this.storageType == StorageTypes.Local) { await this.StateManager.BackupAsync(this.BackupCallbackAsync); } else { await this.StateManager.BackupAsync(this.BackupCallbackAzureAsync); } } await Task.Delay(TimeSpan.FromSeconds(30), cancellationToken); } }
public async Task <string> OrchestrateWorker(WorkerDescription workerDescription) { if (_processorDictionary == null) { this._processorDictionary = this.StateManager .GetOrAddAsync <IReliableDictionary <string, ProcessorInformation> >("orchestrator.ProcessorDictionary").Result; } ServiceEventSource.Current.ServiceMessage(this.Context, $"Orchestrate worker called for {workerDescription.Identifier}"); var address = String.Empty; using (var tx = this.StateManager.CreateTransaction()) { var result = await _processorDictionary.TryGetValueAsync(tx, workerDescription.Identifier); if (result.HasValue) { var info = result.Value; await _processorDictionary.TryUpdateAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = info.Address, TicksLastUpdated = DateTime.UtcNow.Ticks }, info); await tx.CommitAsync(); address = info.Address; } else { // spin up the new service here ServiceEventSource.Current.ServiceMessage(this.Context, $"Creating processor for {workerDescription.Identifier}"); var appName = Context.CodePackageActivationContext.ApplicationName; var svcName = $"{appName}/{Names.ProcessorSuffix}/{workerDescription.Identifier}"; await _fabricClient.ServiceManager.CreateServiceAsync(new StatefulServiceDescription() { HasPersistedState = true, PartitionSchemeDescription = new UniformInt64RangePartitionSchemeDescription(1), ServiceTypeName = Names.ProcessorTypeName, ApplicationName = new System.Uri(appName), ServiceName = new System.Uri(svcName) }); ServiceEventSource.Current.ServiceMessage(this.Context, $"Processor for {workerDescription.Identifier} running on {svcName}"); await _processorDictionary.AddAsync(tx, workerDescription.Identifier, new ProcessorInformation() { Address = svcName, TicksLastUpdated = DateTime.UtcNow.Ticks }); address = svcName; await tx.CommitAsync(); } } return(address); }