Skip to content

Commit

Permalink
ChangeFeedProcessor: Fixes log during lease release (#2764)
Browse files Browse the repository at this point in the history
* catch 404

* test

* text

* Filtering substatus

* Test name
  • Loading branch information
ealsur authored Oct 4, 2021
1 parent 7452ef7 commit 919bb3b
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Microsoft.Azure.Cosmos.ChangeFeed.LeaseManagement
{
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.ChangeFeed.Exceptions;
Expand Down Expand Up @@ -147,9 +148,22 @@ public override Task<DocumentServiceLease> CreateLeaseIfNotExistAsync(
public override async Task ReleaseAsync(DocumentServiceLease lease)
{
if (lease == null)
{
throw new ArgumentNullException(nameof(lease));
}

DocumentServiceLease refreshedLease;
try
{
refreshedLease = await this.TryGetLeaseAsync(lease).ConfigureAwait(false);
}
catch (CosmosException cosmosException)
when (cosmosException.StatusCode == HttpStatusCode.NotFound && cosmosException.SubStatusCode == (int)SubStatusCodes.Unknown)
{
// Lease is being released after a split, the split itself delete the lease, this is expected
return;
}

DocumentServiceLease refreshedLease = await this.TryGetLeaseAsync(lease).ConfigureAwait(false);
if (refreshedLease == null)
{
DefaultTrace.TraceInformation("Lease with token {0} failed to release lease. The lease is gone already.", lease.CurrentLeaseToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,104 @@ public async Task ReleaseCompletes()
await documentServiceLeaseManagerCosmos.ReleaseAsync(lease);
}

/// <summary>
/// Verifies a Release when the lease has already been deleted does not throw
/// </summary>
[TestMethod]
public async Task ReleaseWhenNotExistDoesNotThrow()
{
DocumentServiceLeaseStoreManagerOptions options = new DocumentServiceLeaseStoreManagerOptions
{
HostName = Guid.NewGuid().ToString()
};

DocumentServiceLeaseCore lease = new DocumentServiceLeaseCore()
{
LeaseId = Guid.NewGuid().ToString(),
LeaseToken = "0",
Owner = Guid.NewGuid().ToString(),
FeedRange = new FeedRangePartitionKeyRange("0")
};

Mock<DocumentServiceLeaseUpdater> mockUpdater = new Mock<DocumentServiceLeaseUpdater>();

ResponseMessage leaseResponse = new ResponseMessage(System.Net.HttpStatusCode.NotFound);

Mock<ContainerInternal> mockedContainer = new Mock<ContainerInternal>();
mockedContainer.Setup(c => c.ReadItemStreamAsync(
It.Is<string>(id => id == lease.LeaseId),
It.IsAny<PartitionKey>(),
It.IsAny<ItemRequestOptions>(),
It.IsAny<CancellationToken>())).ReturnsAsync(leaseResponse);


DocumentServiceLeaseManagerCosmos documentServiceLeaseManagerCosmos = new DocumentServiceLeaseManagerCosmos(
Mock.Of<ContainerInternal>(),
mockedContainer.Object,
mockUpdater.Object,
options,
Mock.Of<RequestOptionsFactory>());

await documentServiceLeaseManagerCosmos.ReleaseAsync(lease);

mockUpdater.Verify(c => c.UpdateLeaseAsync(
It.IsAny<DocumentServiceLease>(),
It.IsAny<string>(),
It.IsAny<PartitionKey>(),
It.IsAny<Func<DocumentServiceLease, DocumentServiceLease>>()), Times.Never);
}

/// <summary>
/// Verifies a Release when attempting to access the lease returns a 404 with some particular substatus
/// </summary>
[TestMethod]
public async Task ReleaseWhen404WithSomeSubstatusDoesThrow()
{
DocumentServiceLeaseStoreManagerOptions options = new DocumentServiceLeaseStoreManagerOptions
{
HostName = Guid.NewGuid().ToString()
};

DocumentServiceLeaseCore lease = new DocumentServiceLeaseCore()
{
LeaseId = Guid.NewGuid().ToString(),
LeaseToken = "0",
Owner = Guid.NewGuid().ToString(),
FeedRange = new FeedRangePartitionKeyRange("0")
};

Mock<DocumentServiceLeaseUpdater> mockUpdater = new Mock<DocumentServiceLeaseUpdater>();

ResponseMessage leaseResponse = new ResponseMessage(System.Net.HttpStatusCode.NotFound);
leaseResponse.Headers.SubStatusCode = Documents.SubStatusCodes.ReadSessionNotAvailable;

Mock<ContainerInternal> mockedContainer = new Mock<ContainerInternal>();
mockedContainer.Setup(c => c.ReadItemStreamAsync(
It.Is<string>(id => id == lease.LeaseId),
It.IsAny<PartitionKey>(),
It.IsAny<ItemRequestOptions>(),
It.IsAny<CancellationToken>())).ReturnsAsync(leaseResponse);


DocumentServiceLeaseManagerCosmos documentServiceLeaseManagerCosmos = new DocumentServiceLeaseManagerCosmos(
Mock.Of<ContainerInternal>(),
mockedContainer.Object,
mockUpdater.Object,
options,
Mock.Of<RequestOptionsFactory>());

CosmosException cosmosException = await Assert.ThrowsExceptionAsync<CosmosException>(() => documentServiceLeaseManagerCosmos.ReleaseAsync(lease));

Assert.AreEqual(System.Net.HttpStatusCode.NotFound, cosmosException.StatusCode);
Assert.AreEqual((int)Documents.SubStatusCodes.ReadSessionNotAvailable, cosmosException.SubStatusCode);

mockUpdater.Verify(c => c.UpdateLeaseAsync(
It.IsAny<DocumentServiceLease>(),
It.IsAny<string>(),
It.IsAny<PartitionKey>(),
It.IsAny<Func<DocumentServiceLease, DocumentServiceLease>>()), Times.Never);
}

/// <summary>
/// Verifies that if the updater read a different Owner from the captured in memory, throws a LeaseLost
/// </summary>
Expand Down

0 comments on commit 919bb3b

Please sign in to comment.