Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions src/Foundatio.AzureStorage/Extensions/StorageExtensions.cs

This file was deleted.

4 changes: 2 additions & 2 deletions src/Foundatio.AzureStorage/Foundatio.AzureStorage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<PackageTags>Queue;Messaging;Message;File;Distributed;Storage;Blob;Azure</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Storage.Blob" Version="11.2.3" />
<PackageReference Include="Microsoft.Azure.Storage.Queue" Version="11.2.3" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.24.0" />
<PackageReference Include="Azure.Storage.Queues" Version="12.22.0" />

<PackageReference Include="Foundatio" Version="12.0.0" Condition="'$(ReferenceFoundatioSource)' == '' OR '$(ReferenceFoundatioSource)' == 'false'" />
<ProjectReference Include="..\..\..\Foundatio\src\Foundatio\Foundatio.csproj" Condition="'$(ReferenceFoundatioSource)' == 'true'" />
Expand Down
188 changes: 133 additions & 55 deletions src/Foundatio.AzureStorage/Queues/AzureStorageQueue.cs

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions src/Foundatio.AzureStorage/Queues/AzureStorageQueueEntry.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
using Microsoft.Azure.Storage.Queue;
using System;
using Azure.Storage.Queues.Models;

namespace Foundatio.Queues;

public class AzureStorageQueueEntry<T> : QueueEntry<T> where T : class
{
public CloudQueueMessage UnderlyingMessage { get; }
public QueueMessage UnderlyingMessage { get; }

public AzureStorageQueueEntry(CloudQueueMessage message, T value, IQueue<T> queue)
: base(message.Id, null, value, queue, message.InsertionTime.GetValueOrDefault().UtcDateTime, message.DequeueCount)
{
/// <summary>
/// The current pop receipt for this message. This gets updated after each
/// UpdateMessageAsync call (renew lock, abandon with retry delay).
/// </summary>
public string PopReceipt { get; internal set; }

public AzureStorageQueueEntry(QueueMessage message, T data, IQueue<T> queue)
: base(message.MessageId, null, data, queue, message.InsertedOn?.UtcDateTime ?? DateTime.MinValue, (int)message.DequeueCount)
{
UnderlyingMessage = message;
PopReceipt = message.PopReceipt;
}
}
102 changes: 95 additions & 7 deletions src/Foundatio.AzureStorage/Queues/AzureStorageQueueOptions.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,120 @@
using System;
using Microsoft.Azure.Storage.RetryPolicies;
using Azure.Core;

namespace Foundatio.Queues;

public class AzureStorageQueueOptions<T> : SharedQueueOptions<T> where T : class
{
public string ConnectionString { get; set; }
public IRetryPolicy RetryPolicy { get; set; }

/// <summary>
/// The interval to wait between polling for new messages when the queue is empty.
/// </summary>
public TimeSpan DequeueInterval { get; set; } = TimeSpan.FromSeconds(2);

/// <summary>
/// A function that returns the delay before retrying a failed message based on the attempt number.
/// Default is exponential backoff with jitter: 2^attempt seconds + random 0-100ms.
/// </summary>
public Func<int, TimeSpan> RetryDelay { get; set; } = attempt =>
TimeSpan.FromSeconds(Math.Pow(2, attempt)) + TimeSpan.FromMilliseconds(Random.Shared.Next(0, 100));

/// <summary>
/// When true, messages are Base64-encoded for backward compatibility with the legacy
/// Microsoft.Azure.Storage.Queue SDK (v11). The v11 SDK encoded all messages as Base64
/// by default, while the v12 Azure.Storage.Queues SDK does not.
///
/// <para><b>Default:</b> false (v12 behavior - no encoding)</para>
///
/// <para><b>When to enable:</b> Only enable this if you have existing messages in your
/// queue that were written using the v11 SDK and need to be read during migration.</para>
///
/// <para><b>Migration path:</b></para>
/// <list type="number">
/// <item><description>Enable UseBase64Encoding=true to read existing v11 messages</description></item>
/// <item><description>Process all existing messages from the queue</description></item>
/// <item><description>Once queue is empty, disable UseBase64Encoding (set to false)</description></item>
/// <item><description>All new messages will use raw encoding (v12 default)</description></item>
/// </list>
///
/// <para><b>Deprecation notice:</b> This option exists solely for migration purposes
/// and may be removed in a future major version. Plan to migrate away from Base64
/// encoding as soon as practical.</para>
/// </summary>
public bool UseBase64Encoding { get; set; }

/// <summary>
/// Optional action to configure Azure SDK retry options.
/// Default Azure SDK retry settings: MaxRetries=3, Delay=0.8s, MaxDelay=1min, Mode=Exponential.
/// </summary>
/// <example>
/// <code>
/// options.ConfigureRetry = retry =>
/// {
/// retry.MaxRetries = 5;
/// retry.Delay = TimeSpan.FromSeconds(1);
/// retry.Mode = RetryMode.Exponential;
/// };
/// </code>
/// </example>
public Action<RetryOptions> ConfigureRetry { get; set; }
}

public class AzureStorageQueueOptionsBuilder<T> : SharedQueueOptionsBuilder<T, AzureStorageQueueOptions<T>, AzureStorageQueueOptionsBuilder<T>> where T : class
{
public AzureStorageQueueOptionsBuilder<T> ConnectionString(string connectionString)
{
Target.ConnectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
ArgumentException.ThrowIfNullOrEmpty(connectionString);

Target.ConnectionString = connectionString;
return this;
}

public AzureStorageQueueOptionsBuilder<T> RetryPolicy(IRetryPolicy retryPolicy)
public AzureStorageQueueOptionsBuilder<T> DequeueInterval(TimeSpan dequeueInterval)
{
Target.RetryPolicy = retryPolicy ?? throw new ArgumentNullException(nameof(retryPolicy));
Target.DequeueInterval = dequeueInterval;
return this;
}

public AzureStorageQueueOptionsBuilder<T> DequeueInterval(TimeSpan dequeueInterval)
/// <summary>
/// Sets a custom retry delay function for failed messages.
/// </summary>
/// <param name="retryDelay">A function that takes the attempt number and returns the delay before the next retry.</param>
public AzureStorageQueueOptionsBuilder<T> RetryDelay(Func<int, TimeSpan> retryDelay)
{
Target.DequeueInterval = dequeueInterval;
ArgumentNullException.ThrowIfNull(retryDelay);

Target.RetryDelay = retryDelay;
return this;
}

/// <summary>
/// Enables Base64 message encoding for backward compatibility with the legacy v11 SDK.
/// See <see cref="AzureStorageQueueOptions{T}.UseBase64Encoding"/> for migration guidance.
/// </summary>
public AzureStorageQueueOptionsBuilder<T> UseBase64Encoding(bool useBase64Encoding = true)
{
Target.UseBase64Encoding = useBase64Encoding;
return this;
}

/// <summary>
/// Configures Azure SDK retry options for transient failure handling.
/// </summary>
/// <param name="configure">Action to configure retry options.</param>
/// <example>
/// <code>
/// .ConfigureRetry(retry =>
/// {
/// retry.MaxRetries = 5;
/// retry.Delay = TimeSpan.FromSeconds(1);
/// })
/// </code>
/// </example>
public AzureStorageQueueOptionsBuilder<T> ConfigureRetry(Action<RetryOptions> configure)
{
ArgumentNullException.ThrowIfNull(configure);
Target.ConfigureRetry = configure;
return this;
}
}
Loading
Loading