Skip to content

Commit

Permalink
fix: do not recreate Random each time (#945)
Browse files Browse the repository at this point in the history
* fix: do not recreate Random each time

On .NET Framework it is incorrect to recreate Random instances each time, these should instead be one per instance. On .NET Core and later this is not a limitation, but the libraries share a codebase.

Fixes #944

* Use a thread safe Random instance #944

* Forgot to commit csproj change #944

* Address PR comment #944
  • Loading branch information
watfordsuzy authored Apr 15, 2024
1 parent b410dfd commit d03b1ce
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Box.V2/Box.V2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@
<Compile Include="Utility\ContentTypeMapper.cs" />
<Compile Include="Utility\Retry.cs" />
<Compile Include="Utility\SharedLinkUtils.cs" />
<Compile Include="Utility\ThreadSafeRandom.cs" />
<Compile Include="Wrappers\BoxError.cs" />
<Compile Include="Wrappers\BoxErrorContextInfo.cs" />
<Compile Include="Wrappers\BoxBinaryRequest.cs" />
Expand Down Expand Up @@ -343,4 +344,4 @@
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>
5 changes: 3 additions & 2 deletions Box.V2/Utility/ExponentialBackoff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ public TimeSpan GetRetryTimeout(int numRetries)
const double RETRY_RANDOMIZATION_FACTOR = 0.5;
var minRandomization = 1 - RETRY_RANDOMIZATION_FACTOR;
var maxRandomization = 1 + RETRY_RANDOMIZATION_FACTOR;
var random = new Random();

var randomization = random.NextDouble() * (maxRandomization - minRandomization) + minRandomization;
var randomization = ThreadSafeRandom.Instance.NextDouble()
* (maxRandomization - minRandomization) + minRandomization;

var exponential = Math.Pow(2, numRetries - 1);
var result = Math.Ceiling(exponential * baseInterval.TotalSeconds * randomization);
return TimeSpan.FromSeconds(result);
Expand Down
31 changes: 31 additions & 0 deletions Box.V2/Utility/ThreadSafeRandom.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Runtime.CompilerServices;

namespace Box.V2.Utility
{
/// <summary>
/// A thread safe implementation of <see cref="Random"/>, following best practices
/// for .NET Framework and .NET Standard.
/// </summary>
/// <seealso href="https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-random"/>
internal static class ThreadSafeRandom
{
//
// Adapted from https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Random.cs
//
// NOTE: when/if this library updates to .NET 6+, this code can be replaced with `Random.Shared`
//

[ThreadStatic]
private static Random _random;

[MethodImpl(MethodImplOptions.NoInlining)]
private static Random CreateRandom() => _random = new Random();

/// <summary>
/// An instance of <see cref="Random"/> specific to the calling thread.
/// Do not pass this instance to other threads or contexts.
/// </summary>
public static Random Instance => _random ?? CreateRandom();
}
}

0 comments on commit d03b1ce

Please sign in to comment.