public static async Task <Uri> AddToCatalog(CatalogItem catalogItem, string connectionString, string container, string catalogBaseAddress) { StorageWriteLock writeLock = new StorageWriteLock(connectionString, container); await writeLock.AquireAsync(); Uri rootUri = null; Exception exception = null; try { Storage storage = CreateStorage(connectionString, container, catalogBaseAddress); AppendOnlyCatalogWriter writer = new AppendOnlyCatalogWriter(storage); writer.Add(catalogItem); await writer.Commit(); rootUri = writer.RootUri; } catch (Exception e) { exception = e; } await writeLock.ReleaseAsync(); if (exception != null) { throw exception; } return(rootUri); }
public async Task LockFailTest() { var etagOriginal = this.rand.NextString(); var model = new ValueModel { Value = this.rand.NextString() }; model.Locked = true; var dataOriginal = JsonConvert.SerializeObject(model); var @lock = new StorageWriteLock <ValueModel>( this.mockClient.Object, COLL, KEY, (v, b) => v.Locked = b, m => !JsonConvert.DeserializeObject <ValueModel>(m.Data).Locked); this.mockClient .Setup(x => x.GetAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY))) .ReturnsAsync(new ValueApiModel { Data = dataOriginal, ETag = etagOriginal }); var result = await @lock.TryLockAsync(); Assert.False(result.Value); }
public async Task <bool> TryRebuildCacheAsync(bool force = false) { var @lock = new StorageWriteLock <CacheValue>( this.storageClient, CACHE_COLLECTION_ID, CACHE_KEY, (c, b) => c.Rebuilding = b, m => this.NeedBuild(force, m)); while (true) { var locked = await @lock.TryLockAsync(); if (locked == null) { this.log.Warn("Cache rebuilding: lock failed due to conflict. Retry soon", () => { }); continue; } if (!locked.Value) { return(false); } // Build the cache content var twinNamesTask = this.GetValidNamesAsync(); var simulationNamesTask = this.simulationClient.GetDevicePropertyNamesAsync(); try { Task.WaitAll(twinNamesTask, simulationNamesTask); } catch (Exception) { this.log.Warn($"Some underlying service is not ready. Retry after {this.serviceQueryInterval}", () => { }); await @lock.ReleaseAsync(); await Task.Delay(this.serviceQueryInterval); continue; } var twinNames = twinNamesTask.Result; twinNames.ReportedProperties.UnionWith(simulationNamesTask.Result); var updated = await @lock.WriteAndReleaseAsync(new CacheValue { Tags = twinNames.Tags, Reported = twinNames.ReportedProperties }); if (updated) { return(true); } this.log.Warn("Cache rebuilding: write failed due to conflict. Retry soon", () => { }); } }
public async Task ReleaseAndWriteAsyncWithoutLockTest() { var @lock = new StorageWriteLock <ValueModel>( this.mockClient.Object, COLL, KEY, (v, b) => v.Locked = b, m => true); await Assert.ThrowsAsync <ResourceOutOfDateException>(() => @lock.WriteAndReleaseAsync(null)); }
public async Task LockConflictTest() { var etagOriginal = this.rand.NextString(); var model = new ValueModel { Value = this.rand.NextString() }; model.Locked = false; var dataOriginal = JsonConvert.SerializeObject(model); model.Locked = true; var dataLocked = JsonConvert.SerializeObject(model); var @lock = new StorageWriteLock <ValueModel>( this.mockClient.Object, COLL, KEY, (v, b) => v.Locked = b, m => !JsonConvert.DeserializeObject <ValueModel>(m.Data).Locked); this.mockClient .Setup(x => x.GetAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY))) .ReturnsAsync(new ValueApiModel { Data = dataOriginal, ETag = etagOriginal }); this.mockClient .Setup(x => x.UpdateAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY), It.Is <string>(s => s == dataLocked), It.Is <string>(s => s == etagOriginal))) .ThrowsAsync(new ConflictingResourceException()); var result = await @lock.TryLockAsync(); Assert.Null(result); }
/// <summary> /// Try to create cache of deviceProperties if lock failed retry after 10 seconds /// </summary> public async Task <bool> TryRecreateListAsync(bool force = false) { var @lock = new StorageWriteLock <DevicePropertyServiceModel>( this.storageClient, CACHE_COLLECTION_ID, CACHE_KEY, (c, b) => c.Rebuilding = b, m => this.ShouldCacheRebuild(force, m)); while (true) { var locked = await @lock.TryLockAsync(); if (locked == null) { this.log.Warn("Cache rebuilding: lock failed due to conflict. Retry soon", () => { }); continue; } if (!locked.Value) { return(false); } // Build the cache content var twinNamesTask = this.GetValidNamesAsync(); try { Task.WaitAll(twinNamesTask); } catch (Exception) { this.log.Warn( $"Some underlying service is not ready. Retry after {this.serviceQueryInterval}", () => { }); try { await @lock.ReleaseAsync(); } catch (Exception e) { log.Error("Cache rebuilding: Unable to release lock", () => e); } await Task.Delay(this.serviceQueryInterval); continue; } var twinNames = twinNamesTask.Result; try { var updated = await @lock.WriteAndReleaseAsync( new DevicePropertyServiceModel { Tags = twinNames.Tags, Reported = twinNames.ReportedProperties }); if (updated) { this.DevicePropertiesLastUpdated = DateTime.Now; return(true); } } catch (Exception e) { log.Error("Cache rebuilding: Unable to write and release lock", () => e); } this.log.Warn("Cache rebuilding: write failed due to conflict. Retry soon", () => { }); } }
/// <summary> /// Try to create cache of deviceProperties if lock failed retry after 10 seconds /// </summary> public async Task <bool> TryRecreateListAsync(bool force = false) { var @lock = new StorageWriteLock <DevicePropertyServiceModel>( this.storageClient, CACHE_COLLECTION_ID, CACHE_KEY, (c, b) => c.Rebuilding = b, m => this.ShouldCacheRebuild(force, m)); while (true) { //var locked = await @lock.TryLockAsync(); //if (locked == null) //{ // this.log.Warn("Cache rebuilding: lock failed due to conflict. Retry soon", () => { }); // continue; //} //if (!locked.Value) //{ // return false; //} // Build the cache content var twinNamesTask = this.GetValidNamesAsync(); try { Task.WaitAll(twinNamesTask); } catch (Exception) { this.log.Warn( $"Some underlying service is not ready. Retry after {this.serviceQueryInterval}", () => { }); try { //await @lock.ReleaseAsync(); } catch (Exception e) { log.Error("Cache rebuilding: Unable to release lock", () => e); } await Task.Delay(this.serviceQueryInterval); continue; } var twinNames = twinNamesTask.Result; try { var model = await this.storageClient.GetAllAsync(CACHE_COLLECTION_ID); foreach (var item in model.Items) { await this.storageClient.DeleteAsync(CACHE_COLLECTION_ID, item.objectid); } DevicePropertyServiceModel devicepropertites = new DevicePropertyServiceModel(); devicepropertites.Tags = twinNames.Tags; devicepropertites.Reported = twinNames.ReportedProperties; var value = JsonConvert.SerializeObject(devicepropertites, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var Createdevicepropertites = await this.storageClient.CreateAsync(CACHE_COLLECTION_ID, value); //var updated = await @lock.WriteAndReleaseAsync( // new DevicePropertyServiceModel // { // Tags = twinNames.Tags, // Reported = twinNames.ReportedProperties // }); if (Createdevicepropertites.objectid != null) { this.DevicePropertiesLastUpdated = DateTime.Now; return(true); } } catch (Exception e) { log.Error("Cache rebuilding: Unable to write and release lock", () => e); } this.log.Warn("Cache rebuilding: write failed due to conflict. Retry soon", () => { }); } }
public async Task NormalLoopTest() { var etagOriginal = this.rand.NextString(); var etagLocked = this.rand.NextString(); var etagUpdated = this.rand.NextString(); var model = new ValueModel { Value = this.rand.NextString() }; model.Locked = false; var dataOriginal = JsonConvert.SerializeObject(model); model.Locked = true; var dataLocked = JsonConvert.SerializeObject(model); model.Value = this.rand.NextString(); model.Locked = false; var dataUpdated = JsonConvert.SerializeObject(model); var @lock = new StorageWriteLock <ValueModel>( this.mockClient.Object, COLL, KEY, (v, b) => v.Locked = b, m => !JsonConvert.DeserializeObject <ValueModel>(m.Data).Locked); this.mockClient .Setup(x => x.GetAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY))) .ReturnsAsync(new ValueApiModel { Data = dataOriginal, ETag = etagOriginal }); this.mockClient .Setup(x => x.UpdateAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY), It.Is <string>(s => s == dataLocked), It.Is <string>(s => s == etagOriginal))) .ReturnsAsync(new ValueApiModel { ETag = etagLocked }); var lockResult = await @lock.TryLockAsync(); Assert.True(lockResult.Value); this.mockClient .Verify(x => x.GetAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY)), Times.Once); this.mockClient .Verify(x => x.GetAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY)), Times.Once); this.mockClient .Verify(x => x.UpdateAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY), It.Is <string>(s => s == dataLocked), It.Is <string>(s => s == etagOriginal)), Times.Once); this.mockClient .Setup(x => x.UpdateAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY), It.Is <string>(s => s == dataUpdated), It.Is <string>(s => s == etagLocked))) .ReturnsAsync(new ValueApiModel { ETag = etagUpdated }); var writeResult = await @lock.WriteAndReleaseAsync(model); Assert.True(writeResult); this.mockClient .Verify(x => x.UpdateAsync( It.Is <string>(s => s == COLL), It.Is <string>(s => s == KEY), It.Is <string>(s => s == dataUpdated), It.Is <string>(s => s == etagLocked)), Times.Once); }