public void WhenWorksIsAddedToQueueThenTheyWillBeReturned() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now); var document = CreateTestDocumentId(); queue.PutWork(document); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(); Assert.Contains(document, work); Assert.Empty(queue.TakeWork()); }
public void WhenWorksIsAddedToQueueThenTheyWillBeReturned(AnalyzerWorkType workType) { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, workType); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(workType); Assert.Contains(document, work); Assert.Empty(queue.TakeWork(workType)); }
public async Task WhenWorkIsAddedAgainWhenPreviousIsAnalysing_ThenDontWaitAnotherOneToGetReady() { var now = DateTime.UtcNow; var loggerFactory = new LoggerFactory(); var queue = new AnalyzerWorkQueue(loggerFactory, utcNow: () => now); var document = CreateTestDocumentId(); queue.PutWork(document); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(); var waitingCall = Task.Run(async() => await queue.WaitForResultsAsync(work)); await Task.Delay(50); // User updates code -> document is queued again during period when theres already api call waiting // to continue. queue.PutWork(document); // First iteration of work is done. queue.MarkWorkAsCompleteForDocumentId(document); // Waiting call continues because it's iteration of work is done, even when theres next // already waiting. await waitingCall; Assert.True(waitingCall.IsCompleted); Assert.Empty(loggerFactory.Logger.RecordedMessages); }
public async Task WhenWorkIsAddedAgainWhenPreviousIsAnalysing_ThenDontWaitAnotherOneToGetReady() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(AnalyzerWorkType.Foreground); var waitingCall = Task.Run(async() => await queue.WaitForegroundWorkComplete()); await Task.Delay(50); // User updates code -> document is queued again during period when theres already api call waiting // to continue. queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground); // First iteration of work is done. queue.WorkComplete(AnalyzerWorkType.Foreground); // Waiting call continues because its iteration of work is done, even when theres next // already waiting. await waitingCall; Assert.True(waitingCall.IsCompleted); }
private async Task Worker(AnalyzerWorkType workType) { while (true) { try { var currentWorkGroupedByProjects = _workQueue .TakeWork(workType) .Select(document => (project: document.Project, document)) .GroupBy(x => x.project, x => x.document) .ToImmutableArray(); foreach (var projectGroup in currentWorkGroupedByProjects) { var projectPath = projectGroup.Key.FilePath; EventIfBackgroundWork(workType, projectPath, ProjectDiagnosticStatus.Started); await AnalyzeProject(projectGroup); EventIfBackgroundWork(workType, projectPath, ProjectDiagnosticStatus.Ready); } _workQueue.WorkComplete(workType); await Task.Delay(50); } catch (Exception ex) { _logger.LogError($"Analyzer worker failed: {ex}"); } } }
public void WhenSameItemIsAddedMultipleTimesInRowThenThrottleItemAsOne() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now); var document = CreateTestDocumentId(); queue.PutWork(document); queue.PutWork(document); queue.PutWork(document); Assert.Empty(queue.TakeWork()); now = PassOverThrotlingPeriod(now); Assert.Contains(document, queue.TakeWork()); Assert.Empty(queue.TakeWork()); }
public void WhenSameItemIsAddedMultipleTimesInRowThenThrottleItemAsOne(AnalyzerWorkType workType) { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, workType); queue.PutWork(new[] { document }, workType); queue.PutWork(new[] { document }, workType); Assert.Empty(queue.TakeWork(workType)); now = PassOverThrotlingPeriod(now); Assert.Contains(document, queue.TakeWork(workType)); Assert.Empty(queue.TakeWork(workType)); }
public void WhenItemsAreAddedButThrotlingIsntOverNoWorkShouldBeReturned() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now); var document = CreateTestDocumentId(); queue.PutWork(document); Assert.Empty(queue.TakeWork()); }
public void WhenItemsAreAddedButThrotlingIsntOverNoWorkShouldBeReturned(AnalyzerWorkType workType) { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, workType); Assert.Empty(queue.TakeWork(workType)); }
public void WhenFileIsntAtBackgroundQueueAndTriedToBeQueued_ThenQueue() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new TestLoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.QueueDocumentForeground(document); now = PassOverThrotlingPeriod(now); Assert.Equal(document, queue.TakeWork(AnalyzerWorkType.Foreground).Single()); }
public void WhenFileIsProcessingInBackgroundQueue_ThenPromoteItAsForeground() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, AnalyzerWorkType.Background); now = PassOverThrotlingPeriod(now); var activeWork = queue.TakeWork(AnalyzerWorkType.Background); queue.TryPromote(document); now = PassOverThrotlingPeriod(now); var foregroundWork = queue.TakeWork(AnalyzerWorkType.Foreground); Assert.NotEmpty(foregroundWork); Assert.NotEmpty(activeWork); }
public void WhenFileIsntAtBackgroundQueueAndTriedToBePromoted_ThenDontDoNothing() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.TryPromote(document); now = PassOverThrotlingPeriod(now); Assert.Empty(queue.TakeWork(AnalyzerWorkType.Foreground)); }
public void WhenSingleFileIsQueued_ThenPromoteItFromBackgroundQueueToForeground() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new TestLoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, AnalyzerWorkType.Background); queue.QueueDocumentForeground(document); now = PassOverThrotlingPeriod(now); Assert.NotEmpty(queue.TakeWork(AnalyzerWorkType.Foreground)); }
public void WhenWorkIsWaitedButTimeoutForWaitIsExceededAllowContinue() { var now = DateTime.UtcNow; var loggerFactory = new LoggerFactory(); var queue = new AnalyzerWorkQueue(loggerFactory, utcNow: () => now, timeoutForPendingWorkMs: 20); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(AnalyzerWorkType.Foreground); var pendingTask = queue.WaitForegroundWorkComplete(); var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(5)); pendingTask.Wait(cts.Token); Assert.True(pendingTask.IsCompleted); Assert.Contains("Timeout before work got ready", loggerFactory.Logger.RecordedMessages.Single()); }
public void WhenForegroundWorkIsUnderAnalysisOutFromQueueThenWaitUntilNextIterationOfItIsReady() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 500); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(AnalyzerWorkType.Foreground); var pendingTask = queue.WaitForegroundWorkComplete(); pendingTask.Wait(TimeSpan.FromMilliseconds(50)); Assert.False(pendingTask.IsCompleted); queue.WorkComplete(AnalyzerWorkType.Foreground); pendingTask.Wait(TimeSpan.FromMilliseconds(50)); Assert.True(pendingTask.IsCompleted); }
public void WhenWorkIsAddedThenWaitNextIterationOfItReady() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 500); var document = CreateTestDocumentId(); queue.PutWork(document); var pendingTask = queue.WaitForResultsAsync(new [] { document }.ToImmutableArray()); pendingTask.Wait(TimeSpan.FromMilliseconds(50)); Assert.False(pendingTask.IsCompleted); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(); queue.MarkWorkAsCompleteForDocumentId(document); pendingTask.Wait(TimeSpan.FromMilliseconds(50)); Assert.True(pendingTask.IsCompleted); }
private async Task Worker(AnalyzerWorkType workType) { while (true) { try { var solution = _workspace.CurrentSolution; var currentWorkGroupedByProjects = _workQueue .TakeWork(workType) .Select(documentId => (projectId: solution.GetDocument(documentId)?.Project?.Id, documentId)) .Where(x => x.projectId != null) .GroupBy(x => x.projectId, x => x.documentId) .ToImmutableArray(); foreach (var projectGroup in currentWorkGroupedByProjects) { var projectPath = solution.GetProject(projectGroup.Key).FilePath; EventIfBackgroundWork(workType, projectPath, ProjectDiagnosticStatus.Started); await AnalyzeAndReport(solution, projectGroup); EventIfBackgroundWork(workType, projectPath, ProjectDiagnosticStatus.Ready); } _workQueue.WorkComplete(workType); await Task.Delay(50); } catch (Exception ex) { _logger.LogError($"Analyzer worker failed: {ex}"); } } }