The AnalysisQueueProcessor is a core component of the sql-query-analyzer project responsible for managing the asynchronous execution of SQL query analysis tasks. It implements a producer-consumer pattern, allowing analysis requests to be enqueued and processed concurrently up to a defined limit. The processor tracks the lifecycle of each task from creation to completion, maintains real-time statistics on queue depth and throughput, and provides mechanisms for retrieving results or handling errors via callbacks.
public AnalysisQueueProcessor()- Initializes a new instance of the
AnalysisQueueProcessor. Default configuration values (such asMaxConcurrency) are applied unless exposed via specific setters (not listed in public members).
- Initializes a new instance of the
-
public string EnqueueAnalysis(string query)- Submits a new SQL query string to the analysis queue.
- Parameters:
query: The SQL query string to be analyzed.
- Returns: A unique
stringidentifier (TaskId) for the queued task. - Throws: May throw an exception if the queue is in a stopped state or if the input
queryis invalid (e.g., null or empty), depending on internal validation logic.
-
public void Start()- Initiates the background processing loop. Once started, the processor begins dequeuing items and executing analysis tasks up to the
MaxConcurrencylimit. - Throws: May throw if called when the processor is already running.
- Initiates the background processing loop. Once started, the processor begins dequeuing items and executing analysis tasks up to the
-
public async Task StopAsync()- Gracefully shuts down the processor. This method waits for all currently active tasks to complete before returning. No new tasks will be processed after this method is invoked.
- Returns: A
Taskrepresenting the asynchronous operation.
-
public AnalysisTask? GetTaskStatus(string taskId)- Retrieves the current status and details of a specific task.
- Parameters:
taskId: The unique identifier returned byEnqueueAnalysis.
- Returns: An
AnalysisTaskobject containing status details if the task exists; otherwise,null.
-
public QueueStatistics GetStatistics()- Returns a snapshot of the current queue performance and load metrics.
- Returns: A
QueueStatisticsobject containing counts for queued, active, and processed items.
The AnalysisTask object returned by GetTaskStatus (or represented internally) exposes the following members:
-
public string TaskId- Gets the unique identifier for this specific analysis task.
-
public string Query- Gets the original SQL query string submitted for analysis.
-
public AnalysisTaskStatus Status- Gets the current state of the task (e.g., Queued, Running, Completed, Failed).
-
public DateTime CreatedAt- Gets the timestamp when the task was initially enqueued.
-
public DateTime? StartedAt- Gets the timestamp when the task began execution. Returns
nullif the task has not yet started.
- Gets the timestamp when the task began execution. Returns
-
public DateTime? CompletedAt- Gets the timestamp when the task finished (successfully or with error). Returns
nullif the task is still pending or running.
- Gets the timestamp when the task finished (successfully or with error). Returns
-
public QueryAnalysisResult? Result- Gets the analysis output if the task completed successfully. Returns
nullif the task is incomplete or failed.
- Gets the analysis output if the task completed successfully. Returns
-
public string? ErrorMessage- Gets the error message if the task failed. Returns
nullif the task is successful or incomplete.
- Gets the error message if the task failed. Returns
-
public Action<QueryAnalysisResult>? OnComplete- Gets or sets a callback delegate invoked automatically when the task completes successfully.
-
public TimeSpan GetElapsedTime()- Calculates and returns the total duration of the task. If the task is running, it calculates the time from
StartedAtto the current moment. If completed, it calculates the difference betweenCompletedAtandStartedAt.
- Calculates and returns the total duration of the task. If the task is running, it calculates the time from
-
public int QueuedCount- Gets the number of tasks currently waiting in the queue to be processed.
-
public int ActiveCount- Gets the number of tasks currently being executed.
-
public int MaxConcurrency- Gets or sets the maximum number of tasks allowed to run simultaneously.
-
public int TotalProcessed- Gets the cumulative count of tasks that have been fully processed (completed or failed) since the processor started.
This example demonstrates initializing the processor, submitting a query, and waiting for completion.
using SqlQueryAnalyzer;
// Initialize and start the processor
var processor = new AnalysisQueueProcessor();
processor.MaxConcurrency = 4; // Configure parallelism
processor.Start();
// Enqueue a query
string taskId = processor.EnqueueAnalysis("SELECT * FROM Users WHERE IsActive = 1");
// Poll for status
AnalysisTask? task = null;
while (task == null || task.Status == AnalysisTaskStatus.Queued || task.Status == AnalysisTaskStatus.Running)
{
await Task.Delay(500);
task = processor.GetTaskStatus(taskId);
}
if (task.Status == AnalysisTaskStatus.Completed && task.Result != null)
{
Console.WriteLine($"Analysis complete. Found {task.Result.Issues.Count} issues.");
}
else if (task.Status == AnalysisTaskStatus.Failed)
{
Console.WriteLine($"Analysis failed: {task.ErrorMessage}");
}
// Graceful shutdown
await processor.StopAsync();This example utilizes the OnComplete callback for immediate result handling and monitors queue statistics.
using SqlQueryAnalyzer;
var processor = new AnalysisQueueProcessor();
processor.OnComplete = (result) =>
{
// Global completion handler (if supported by implementation) or per-task
Console.WriteLine($"Task {result.TaskId} finished with severity: {result.Severity}");
};
processor.Start();
// Submit multiple queries
var queries = new[] { "SELECT * FROM Orders", "UPDATE Logs SET Read=1" };
foreach (var q in queries)
{
var id = processor.EnqueueAnalysis(q);
var task = processor.GetTaskStatus(id);
// Set specific callback for this task
if (task != null)
{
task.OnComplete = (res) =>
{
Console.WriteLine($"Specific task {id} completed.");
};
}
}
// Monitor live statistics
var stats = processor.GetStatistics();
Console.WriteLine($"Queue Depth: {stats.QueuedCount}, Active: {stats.ActiveCount}, Total Done: {stats.TotalProcessed}");
await processor.StopAsync();- Thread Safety: The
AnalysisQueueProcessoris designed for concurrent access. Methods likeEnqueueAnalysis,GetTaskStatus, and property accessors on the processor instance are thread-safe. However, modifications to individualAnalysisTaskproperties (such as assigningOnComplete) should ideally occur before the task transitions out of theQueuedstate to avoid race conditions where the task completes before the handler is attached. - Lifecycle Constraints: Calling
EnqueueAnalysisafterStopAsynchas been invoked (or beforeStartis called) may result in exceptions or the task being silently dropped, depending on the internal state machine implementation. Always ensure the processor is in theStartedstate before submitting work. - Resource Cleanup: The
StopAsyncmethod is critical for application shutdown. It ensures that in-flight analysis operations are allowed to finish rather than being abruptly terminated, preventing resource leaks or partial data writes. - Nullability: Consumers must handle nullable return types carefully.
GetTaskStatusreturnsnullfor unknown IDs.StartedAt,CompletedAt,Result, andErrorMessageare conditional based on theStatusenum; accessingResulton a failed task orErrorMessageon a successful task will yieldnull. - Elapsed Time Calculation: The
GetElapsedTimemethod onAnalysisTaskperforms dynamic calculation if the task is still running. Frequent polling of this property during active execution may incur minor overhead, though it is generally negligible.