diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/CHANGELOG.md b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/CHANGELOG.md index 4e7b415c4be08..c2bf2d667debd 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/CHANGELOG.md +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/CHANGELOG.md @@ -3,6 +3,7 @@ ## 5.2.0-beta.1 (Unreleased) ### Features Added +- Added support for `BlobsOptions.MaxDequeueCount` ### Breaking Changes diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/api/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.netstandard2.0.cs b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/api/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.netstandard2.0.cs index 72b2f32ce4da4..c50e94cfa16a9 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/api/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.netstandard2.0.cs +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/api/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.netstandard2.0.cs @@ -44,6 +44,7 @@ public partial class BlobsOptions : Microsoft.Azure.WebJobs.Hosting.IOptionsForm { public BlobsOptions() { } public int MaxDegreeOfParallelism { get { throw null; } set { } } + public int MaxDequeueCount { get { throw null; } set { } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] string Microsoft.Azure.WebJobs.Hosting.IOptionsFormatter.Format() { throw null; } } diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Samples.Function.App.csproj b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Samples.Function.App.csproj index 9cdebf27d6d1d..80128b5c71674 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Samples.Function.App.csproj +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Samples.Function.App.csproj @@ -8,7 +8,8 @@ - + + diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Config/BlobsOptions.cs b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Config/BlobsOptions.cs index 938c6b3c8b668..9aacfa444ed7a 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Config/BlobsOptions.cs +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Config/BlobsOptions.cs @@ -15,7 +15,10 @@ namespace Microsoft.Azure.WebJobs.Host /// public class BlobsOptions : IOptionsFormatter { + private const int DefaultMaxDequeueCount = 5; + private int _maxDegreeOfParallelism; + private int _maxDequeueCount = DefaultMaxDequeueCount; /// /// Constructs a new instance. @@ -43,6 +46,30 @@ public int MaxDegreeOfParallelism } } + /// + /// Gets or sets the number of times to try processing a message before moving it to the poison queue (where + /// possible). + /// + /// + /// Some queues do not have corresponding poison queues, and this property does not apply to them. Specifically, + /// there are no corresponding poison queues for any queue whose name already ends in "-poison" or any queue + /// whose name is already too long to add a "-poison" suffix. + /// + public int MaxDequeueCount + { + get { return _maxDequeueCount; } + + set + { + if (value < 1) + { + throw new ArgumentException("MaxDequeueCount must not be less than 1.", nameof(value)); + } + + _maxDequeueCount = value; + } + } + /// [EditorBrowsable(EditorBrowsableState.Never)] string IOptionsFormatter.Format() diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/SharedBlobQueueListenerFactory.cs b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/SharedBlobQueueListenerFactory.cs index b3a09ca0c2430..1355ce98b6894 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/SharedBlobQueueListenerFactory.cs +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/src/Listeners/SharedBlobQueueListenerFactory.cs @@ -98,6 +98,7 @@ internal static QueuesOptions BlobsOptionsToQueuesOptions(BlobsOptions blobsOpti { BatchSize = batchSize, NewBatchThreshold = newBatchThreshold, + MaxDequeueCount = blobsOptions.MaxDequeueCount }; } diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/Listeners/SharedBlobQueueListenerFactoryTests.cs b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/Listeners/SharedBlobQueueListenerFactoryTests.cs index 7d906ddf4ebe0..52225008e38fa 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/Listeners/SharedBlobQueueListenerFactoryTests.cs +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/Listeners/SharedBlobQueueListenerFactoryTests.cs @@ -8,20 +8,21 @@ namespace Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.Listeners { public class SharedBlobQueueListenerFactoryTests { - [TestCase(100, 32, 68)] - [TestCase(64, 32, 32)] - [TestCase(63, 32, 31)] - [TestCase(62, 32, 30)] - [TestCase(16, 9, 7)] - [TestCase(3, 2, 1)] - [TestCase(2, 2, 0)] - [TestCase(1, 1, 0)] - public void ConvertsBlobOptionsToQueueOptionsCorrectly(int maxDegreeOfParallelism, int expectedBatchSize, int expectedNewBatchThreshold) + [TestCase(100, 32, 68, 6)] + [TestCase(64, 32, 32, 5)] + [TestCase(63, 32, 31, 4)] + [TestCase(62, 32, 30, 4)] + [TestCase(16, 9, 7, 3)] + [TestCase(3, 2, 1, 1)] + [TestCase(2, 2, 0, 1)] + [TestCase(1, 1, 0, 1)] + public void ConvertsBlobOptionsToQueueOptionsCorrectly(int maxDegreeOfParallelism, int expectedBatchSize, int expectedNewBatchThreshold, int maxDequeueCount) { // Arrange var blobOptions = new BlobsOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism, + MaxDequeueCount = maxDequeueCount, }; // Act @@ -30,6 +31,7 @@ public void ConvertsBlobOptionsToQueueOptionsCorrectly(int maxDegreeOfParallelis // Assert Assert.AreEqual(expectedBatchSize, queueOptions.BatchSize); Assert.AreEqual(expectedNewBatchThreshold, queueOptions.NewBatchThreshold); + Assert.AreEqual(maxDequeueCount, queueOptions.MaxDequeueCount); } } } diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/StorageBlobsWebJobsBuilderExtensionsTests.cs b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/StorageBlobsWebJobsBuilderExtensionsTests.cs index 6e4ce20aed80b..c5c9b56ab4f3c 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/StorageBlobsWebJobsBuilderExtensionsTests.cs +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs/tests/StorageBlobsWebJobsBuilderExtensionsTests.cs @@ -18,6 +18,7 @@ public void ConfigureOptions_AppliesValuesCorrectly_Blobs() var values = new Dictionary { { $"{extensionPath}:MaxDegreeOfParallelism", "2" }, + { $"{extensionPath}:MaxDequeueCount", "3" }, }; BlobsOptions options = TestHelpers.GetConfiguredOptions(b => @@ -26,6 +27,7 @@ public void ConfigureOptions_AppliesValuesCorrectly_Blobs() }, values); Assert.AreEqual(2, options.MaxDegreeOfParallelism); + Assert.AreEqual(3, options.MaxDequeueCount); } } } diff --git a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Queues/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.Samples.Function.App.csproj b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Queues/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.Samples.Function.App.csproj index b9ef0b1b295a5..3fee0cdb92609 100644 --- a/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Queues/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.Samples.Function.App.csproj +++ b/sdk/storage/Microsoft.Azure.WebJobs.Extensions.Storage.Queues/samples/functionapp/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.Samples.Function.App.csproj @@ -8,6 +8,7 @@ +