- Implement RedisCounterService for rate limiting - Implement RuleLoader with timer refresh - Implement RiskEvaluator for local rule evaluation - Implement SamplingService for CAP events - Implement CapEventPublisher for async event publishing - Implement FailoverStrategy for Redis failure handling - Add configuration classes and DI extensions - Add unit tests (9 tests) - Add NuGet publishing script
68 lines
2.3 KiB
C#
68 lines
2.3 KiB
C#
using Fengling.RiskControl.Configuration;
|
|
using Fengling.RiskControl.Evaluation;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Globalization;
|
|
|
|
namespace Fengling.RiskControl.Sampling;
|
|
|
|
public interface ISamplingService
|
|
{
|
|
bool ShouldSample(RiskEvaluationResult result);
|
|
}
|
|
|
|
public class SamplingService : ISamplingService
|
|
{
|
|
private readonly RiskControlClientOptions _options;
|
|
private readonly ILogger<SamplingService> _logger;
|
|
private readonly Random _random = new();
|
|
|
|
public SamplingService(
|
|
RiskControlClientOptions options,
|
|
ILogger<SamplingService> logger)
|
|
{
|
|
_options = options;
|
|
_logger = logger;
|
|
}
|
|
|
|
public bool ShouldSample(RiskEvaluationResult result)
|
|
{
|
|
if (!_options.Sampling.Enabled)
|
|
return false;
|
|
|
|
foreach (var rule in _options.Sampling.Rules)
|
|
{
|
|
if (EvaluateCondition(rule.Condition, result))
|
|
{
|
|
var sampleRate = rule.Rate;
|
|
var sampled = _random.NextDouble() < sampleRate;
|
|
_logger.LogDebug("Sampling check: condition={Condition}, rate={Rate}, sampled={Sampled}",
|
|
rule.Condition, sampleRate, sampled);
|
|
return sampled;
|
|
}
|
|
}
|
|
|
|
var defaultSampled = _random.NextDouble() < _options.Sampling.DefaultRate;
|
|
_logger.LogDebug("Default sampling: rate={Rate}, sampled={Sampled}",
|
|
_options.Sampling.DefaultRate, defaultSampled);
|
|
return defaultSampled;
|
|
}
|
|
|
|
private bool EvaluateCondition(string condition, RiskEvaluationResult result)
|
|
{
|
|
return condition switch
|
|
{
|
|
string c when c.Contains("RiskLevel == High", StringComparison.OrdinalIgnoreCase)
|
|
=> result.RiskLevel == RiskLevel.High,
|
|
string c when c.Contains("RiskLevel == Medium", StringComparison.OrdinalIgnoreCase)
|
|
=> result.RiskLevel == RiskLevel.Medium,
|
|
string c when c.Contains("RiskLevel == Low", StringComparison.OrdinalIgnoreCase)
|
|
=> result.RiskLevel == RiskLevel.Low,
|
|
string c when c.Contains("IsBlocked == true", StringComparison.OrdinalIgnoreCase)
|
|
=> result.Blocked,
|
|
string c when c.Contains("BlockedOnly", StringComparison.OrdinalIgnoreCase)
|
|
=> result.Blocked,
|
|
_ => false
|
|
};
|
|
}
|
|
}
|