108 lines
3.3 KiB
C#
Executable File
108 lines
3.3 KiB
C#
Executable File
using Microsoft.Extensions.Logging;
|
|
using System;
|
|
using System.Threading;
|
|
|
|
namespace MarketAlly.AIPlugin.Analysis.Infrastructure
|
|
{
|
|
/// <summary>
|
|
/// Context for analysis operations with resource management
|
|
/// </summary>
|
|
public class AnalysisContext : IDisposable
|
|
{
|
|
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
|
private readonly SemaphoreSlim _concurrencySemaphore;
|
|
private readonly ILogger? _logger;
|
|
private bool _disposed = false;
|
|
|
|
/// <summary>
|
|
/// Cancellation token for the analysis operation
|
|
/// </summary>
|
|
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
|
|
|
/// <summary>
|
|
/// Configuration for the analysis
|
|
/// </summary>
|
|
public AnalysisConfiguration Configuration { get; }
|
|
|
|
/// <summary>
|
|
/// Logger for the analysis context
|
|
/// </summary>
|
|
public ILogger? Logger => _logger;
|
|
|
|
/// <summary>
|
|
/// Semaphore for controlling concurrency
|
|
/// </summary>
|
|
public SemaphoreSlim ConcurrencySemaphore => _concurrencySemaphore;
|
|
|
|
public AnalysisContext(AnalysisConfiguration configuration, ILogger? logger = null)
|
|
{
|
|
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
|
_logger = logger;
|
|
_concurrencySemaphore = new SemaphoreSlim(
|
|
configuration.MaxConcurrentAnalyses,
|
|
configuration.MaxConcurrentAnalyses);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a child context with the same configuration but separate cancellation
|
|
/// </summary>
|
|
public AnalysisContext CreateChildContext()
|
|
{
|
|
ThrowIfDisposed();
|
|
var childContext = new AnalysisContext(Configuration, _logger);
|
|
|
|
// Link the child's cancellation to the parent's
|
|
_cancellationTokenSource.Token.Register(() => childContext._cancellationTokenSource.Cancel());
|
|
|
|
return childContext;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancels the analysis operation
|
|
/// </summary>
|
|
public void Cancel()
|
|
{
|
|
ThrowIfDisposed();
|
|
_cancellationTokenSource.Cancel();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Waits for a concurrency slot to become available
|
|
/// </summary>
|
|
public async Task AcquireConcurrencySlotAsync()
|
|
{
|
|
ThrowIfDisposed();
|
|
await _concurrencySemaphore.WaitAsync(CancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Releases a concurrency slot
|
|
/// </summary>
|
|
public void ReleaseConcurrencySlot()
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
_concurrencySemaphore.Release();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
_cancellationTokenSource?.Cancel();
|
|
_cancellationTokenSource?.Dispose();
|
|
_concurrencySemaphore?.Dispose();
|
|
_disposed = true;
|
|
}
|
|
}
|
|
|
|
private void ThrowIfDisposed()
|
|
{
|
|
if (_disposed)
|
|
{
|
|
throw new ObjectDisposedException(nameof(AnalysisContext));
|
|
}
|
|
}
|
|
}
|
|
} |