aliyun-net-credentials/Policy/NonBlocking.cs (99 lines of code) (raw):
using System;
using System.Threading;
using System.Threading.Tasks;
using Aliyun.Credentials.Logging;
namespace Aliyun.Credentials.Policy
{
public class NonBlocking : IPrefetchStrategy
{
private static readonly ILog Logger = LogProvider.For<NonBlocking>();
private const int MaxConcurrentRefreshes = 100;
private readonly SemaphoreSlim concurrentRefreshLeases =
new SemaphoreSlim(MaxConcurrentRefreshes, MaxConcurrentRefreshes);
// 0: false,1: true, default: 0
private int currentlyRefreshing;
public void Prefetch(Action valueUpdater)
{
if (Interlocked.CompareExchange(ref currentlyRefreshing, 1, 0) != 0)
{
return;
}
// 判断是否存在可用的资源
if (!concurrentRefreshLeases.Wait(0))
{
Logger.Warn("Skipping a background refresh task because there are too many other tasks running.");
// 将状态重置为 false
Interlocked.Exchange(ref currentlyRefreshing, 0);
return;
}
try
{
Task.Run(() =>
{
try
{
valueUpdater.Invoke();
}
catch (Exception ex)
{
Logger.Warn(ex.Message);
throw;
}
finally
{
concurrentRefreshLeases.Release();
Interlocked.Exchange(ref currentlyRefreshing, 0);
}
});
}
catch (Exception ex)
{
concurrentRefreshLeases.Release();
Interlocked.Exchange(ref currentlyRefreshing, 0);
Logger.Warn(ex.Message);
throw;
}
}
public async Task PrefetchAsync(Func<Task> valueUpdater)
{
if (Interlocked.CompareExchange(ref currentlyRefreshing, 1, 0) != 0)
{
return;
}
// 判断是否存在可用的资源
if (!await concurrentRefreshLeases.WaitAsync(0))
{
Logger.Warn("Skipping a background refresh task because there are too many other tasks running.");
// 将状态重置为 false
Interlocked.Exchange(ref currentlyRefreshing, 0);
return;
}
try
{
Task.Run(async () =>
{
try
{
await valueUpdater.Invoke();
}
catch (Exception ex)
{
Logger.Warn(ex.Message);
throw;
}
finally
{
concurrentRefreshLeases.Release();
Interlocked.Exchange(ref currentlyRefreshing, 0);
}
});
}
catch (Exception ex)
{
Logger.Warn(ex.Message);
concurrentRefreshLeases.Release();
Interlocked.Exchange(ref currentlyRefreshing, 0);
throw;
}
}
public void Dispose()
{
concurrentRefreshLeases.Dispose();
}
}
}