public void ItTriesToLockRecordThatIsNotExpired() { // Arrange var id = "123"; var ownerId = "foo"; var ownerType = "bar"; var lockDurationSeconds = 5; IResourceResponse <Document> record = BuildResponseWithDocument( id: id, lockOwnerId: ownerId, lockOwnerType: ownerType, lockExpirationUtcMsecs: Now + testOffsetMs, expired: false); this.cosmosDbSql.Setup(x => x.ReadAsync(It.IsAny <IDocumentClient>(), this.storageConfig, id)) .ReturnsAsync(record); // Act bool result = this.target.TryToLockAsync(id, ownerId, ownerType, lockDurationSeconds) .CompleteOrTimeout().Result; // Assert Assert.True(result); }
public void ItTriesToUnlockRecord() { // Arrange var id = Guid.NewGuid().ToString(); var ownerId = Guid.NewGuid().ToString(); var ownerType = Guid.NewGuid().ToString(); IResourceResponse <Document> record = BuildResponseWithDocument( id: id, lockOwnerId: ownerId, lockOwnerType: ownerType, lockExpirationUtcMsecs: Now + testOffsetMs, expired: false); this.cosmosDbSql.Setup(x => x.ReadAsync(It.IsAny <IDocumentClient>(), this.storageConfig, id)) .ReturnsAsync(record); // Act this.target.TryToUnlockAsync(id, ownerId, ownerType).CompleteOrTimeout(); // Assert this.cosmosDbSql.Verify( x => x.UpsertAsync( It.IsAny <IDocumentClient>(), It.IsAny <Config>(), It.IsAny <Resource>() ), Times.Once()); }
/// <summary> /// Выполняет синхронный запрос ресурса /// </summary> /// <returns></returns> public async Task <IResourceResponse> GetResponse(IResourceConfig config = null) { if (CheckCurrentCanBeReturned()) { return(Response); } config = config ?? Config ?? ResourceConfig.Default; if (ResourceRequestState.Init == State) { if (null == Response) { Response = await InternalGetResponse(config); } } if (ResourceRequestState.Error == State) { if (null == LastError) { LastError = new ResourceException("some error in request"); } throw LastError; } return(Response); }
private async Task <(bool found, IDataRecord record)> RetrieveAsync(string id, bool throwIfNotFound) { await this.SetupStorageAsync(); try { this.log.Debug("Fetching record...", () => new { this.storageName, id }); IResourceResponse <Document> response = await this.cosmosDbSql.ReadAsync(this.cosmosDbSqlClient, this.storageConfig, id); this.log.Debug("Record fetched", () => new { this.storageName, id }); Document document = response?.Resource; if (document == null) { if (throwIfNotFound) { throw new ResourceNotFoundException($"The resource {id} doesn't exist."); } return(false, null); } var record = this.DocumentToRecord(document); if (record.IsExpired()) { this.log.Debug("The record requested has expired, deleting...", () => new { this.storageName, id }); await this.TryToDeleteExpiredRecord(id); this.log.Debug("Expired record deleted", () => new { this.storageName, id }); if (throwIfNotFound) { throw new ResourceNotFoundException($"The record '{id}' doesn't exist."); } return(false, null); } return(true, record); } catch (CustomException) { throw; } catch (DocumentClientException e) when(e.StatusCode == HttpStatusCode.NotFound) { this.log.Debug("The record requested doesn't exist.", () => new { this.storageName, id }); if (throwIfNotFound) { throw new ResourceNotFoundException($"The record '{id}' doesn't exist."); } return(false, null); } catch (Exception e) { this.log.Error("Unexpected error while reading from Cosmos DB SQL", () => new { this.storageName, id, e }); throw new ExternalDependencyException(e); } }
public static async Task <DocumentCollection> GetDocumentCollectionAsync( this IChangeFeedDocumentClient client, DocumentCollectionInfo collectionInfo) { Uri collectionUri = UriFactory.CreateDocumentCollectionUri(collectionInfo.DatabaseName, collectionInfo.CollectionName); IResourceResponse <DocumentCollection> response = await client.ReadDocumentCollectionAsync(collectionUri, new RequestOptions()).ConfigureAwait(false); return(response.Resource); }
/// <summary> /// /// </summary> /// <param name="requestIdentifier"></param> /// <param name="response"></param> /// <returns></returns> public static ResponseMetadata FromOffset(string requestIdentifier, IResourceResponse <Document> response) { return(new ResponseMetadata { RequestIdentifier = requestIdentifier, CurrentResourceQuotaUsage = response.CurrentResourceQuotaUsage, MaxResourceQuota = response.MaxResourceQuota, RequestCharge = response.RequestCharge }); }
// Note: requestOptions are only used for read and not for update. public async Task <ILease> UpdateLeaseAsync( ILease cachedLease, Uri documentUri, RequestOptions requestOptions, Func <ILease, ILease> updateLease, bool retryOnConflict) { ILease lease = cachedLease; for (int retryCount = retryOnConflict ? RetryCountOnConflict : 0; retryCount >= 0; retryCount--) { lease = updateLease(lease); if (lease == null) { return(null); } lease.Timestamp = DateTime.UtcNow; Document leaseDocument = await this.TryReplaceLeaseAsync(lease, documentUri).ConfigureAwait(false); if (leaseDocument != null) { return(DocumentServiceLease.FromDocument(leaseDocument)); } Logger.InfoFormat("Partition {0} lease update conflict. Reading the current version of lease.", lease.PartitionId); Document document; try { IResourceResponse <Document> response = await this.client.ReadDocumentAsync( documentUri, requestOptions).ConfigureAwait(false); document = response.Resource; } catch (DocumentClientException ex) when(ex.StatusCode == HttpStatusCode.NotFound) { Logger.InfoFormat("Partition {0} lease no longer exists", lease.PartitionId); throw new LeaseLostException(lease); } DocumentServiceLease serverLease = DocumentServiceLease.FromDocument(document); Logger.InfoFormat( "Partition {0} update failed because the lease with token '{1}' was updated by host '{2}' with token '{3}'. Will retry, {4} retry(s) left.", lease.PartitionId, lease.ConcurrencyToken, serverLease.Owner, serverLease.ConcurrencyToken, retryCount); lease = serverLease; } throw new LeaseLostException(lease); }
public static async Task <Document> TryCreateDocumentAsync(this IChangeFeedDocumentClient client, string collectionLink, object document) { try { IResourceResponse <Document> response = await client.CreateDocumentAsync(collectionLink, document).ConfigureAwait(false); return(response.Resource); } catch (DocumentClientException ex) when(ex.StatusCode == HttpStatusCode.Conflict) { return(null); // Ignore -- document already exists. } }
public ValueServiceModel(IResourceResponse <Document> response) { if (response == null) { return; } var resource = response.Resource; this.CollectionId = resource.GetPropertyValue <string>("CollectionId"); this.Key = resource.GetPropertyValue <string>("Key"); this.Data = resource.GetPropertyValue <string>("Data"); this.ETag = resource.ETag; this.Timestamp = resource.Timestamp; }
public static async Task <Document> TryDeleteDocumentAsync( this IChangeFeedDocumentClient client, Uri documentUri, RequestOptions requestOptions = null) { try { IResourceResponse <Document> response = await client.DeleteDocumentAsync(documentUri, requestOptions).ConfigureAwait(false); return(response.Resource); } catch (DocumentClientException ex) when(ex.StatusCode == HttpStatusCode.NotFound) { return(null); // Ignore -- document not found. } }
public static async Task <Document> TryGetDocumentAsync(this IChangeFeedDocumentClient client, Uri documentUri) { try { IResourceResponse <Document> response = await client.ReadDocumentAsync(documentUri).ConfigureAwait(false); return(response.Resource); } catch (DocumentClientException ex) { if (ex.StatusCode != HttpStatusCode.NotFound) { throw; } } return(null); }
public void ItDeletesExpiredRecordsOnExistsCheck() { // Arrange const string ID_NEW = "new"; const string ID_OLD = "old"; IResourceResponse <Document> response1 = BuildResponseWithDocument(id: ID_NEW, expired: false); IResourceResponse <Document> response2 = BuildResponseWithDocument(id: ID_OLD, expired: true); this.cosmosDbSql.Setup(x => x.ReadAsync(It.IsAny <IDocumentClient>(), this.storageConfig, ID_NEW)) .ReturnsAsync(response1); this.cosmosDbSql.Setup(x => x.ReadAsync(It.IsAny <IDocumentClient>(), this.storageConfig, ID_OLD)) .ReturnsAsync(response2); // Act this.target.ExistsAsync(ID_NEW).CompleteOrTimeout(); this.target.ExistsAsync(ID_OLD).CompleteOrTimeout(); // Assert this.cosmosDbSql.Verify(x => x.DeleteAsync(this.cosmosDbSqlClient.Object, this.storageConfig, ID_NEW), Times.Never); this.cosmosDbSql.Verify(x => x.DeleteAsync(this.cosmosDbSqlClient.Object, this.storageConfig, ID_OLD), Times.Once); }
public void ItReturnsFalseWhenUnlockingRecordThatIsLockedByOther() { // Arrange var id = Guid.NewGuid().ToString(); var ownerId = Guid.NewGuid().ToString(); var ownerType = Guid.NewGuid().ToString(); IResourceResponse <Document> record = BuildResponseWithDocument( id: id, lockOwnerId: ownerId, lockOwnerType: ownerType, lockExpirationUtcMsecs: Now + testOffsetMs, expired: false); this.cosmosDbSql.Setup(x => x.ReadAsync(It.IsAny <IDocumentClient>(), this.storageConfig, id)) .ReturnsAsync(record); // Act bool result = this.target.TryToUnlockAsync(id, "wrongOwner", ownerType).CompleteOrTimeout().Result; // Assert Assert.False(result); }
private async Task <Document> TryReplaceLeaseAsync(ILease lease, Uri leaseUri) { try { IResourceResponse <Document> response = await this.client.ReplaceDocumentAsync(leaseUri, lease, this.CreateIfMatchOptions(lease)).ConfigureAwait(false); return(response.Resource); } catch (DocumentClientException ex) when(ex.StatusCode == HttpStatusCode.PreconditionFailed) { return(null); } catch (DocumentClientException ex) { Logger.WarnFormat("Lease operation exception, status code: ", ex.StatusCode); if (ex.StatusCode == HttpStatusCode.Conflict || ex.StatusCode == HttpStatusCode.NotFound) { throw new LeaseLostException(lease, ex, ex.StatusCode == HttpStatusCode.NotFound); } throw; } }
public void ItCanCheckIfARecordExists() { // Arrange const string ID_NEW = "new"; const string ID_OLD = "old"; const string ID_MISSING = "xyz"; IResourceResponse <Document> response1 = BuildResponseWithDocument(id: ID_NEW, expired: false); IResourceResponse <Document> response2 = BuildResponseWithDocument(id: ID_OLD, expired: true); this.cosmosDbSql.Setup(x => x.ReadAsync(It.IsAny <IDocumentClient>(), this.storageConfig, ID_NEW)) .ReturnsAsync(response1); this.cosmosDbSql.Setup(x => x.ReadAsync(It.IsAny <IDocumentClient>(), this.storageConfig, ID_OLD)) .ReturnsAsync(response2); // Act var result1 = this.target.ExistsAsync(ID_NEW).CompleteOrTimeout().Result; var result2 = this.target.ExistsAsync(ID_OLD).CompleteOrTimeout().Result; var result3 = this.target.ExistsAsync(ID_MISSING).CompleteOrTimeout().Result; // Assert Assert.True(result1); Assert.False(result2); Assert.False(result3); }
private T ParseResponseDocument(IResourceResponse <AzureDocument> response) { var document = JsonConvert.DeserializeObject <T>(response.Resource.ToString()); return(document); }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> /// <filterpriority>2</filterpriority> public void Dispose() { Config = null; Response = null; }