public async Task WhenMultipleThreadsAreConsumingAnalyzerWorkerQueueItWorksAsExpected() { var now = DateTime.UtcNow; var queue = new AnalyzerWorkQueue(new LoggerFactory(), utcNow: () => now, timeoutForPendingWorkMs: 1000); var parallelQueues = Enumerable.Range(0, 10) .Select(_ => Task.Run(() => { var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, AnalyzerWorkType.Foreground); now = PassOverThrotlingPeriod(now); var work = queue.TakeWork(AnalyzerWorkType.Foreground); var pendingTask = queue.WaitForegroundWorkComplete(); queue.WaitForegroundWorkComplete(); pendingTask.Wait(TimeSpan.FromMilliseconds(300)); })) .ToArray(); await Task.WhenAll(parallelQueues); Assert.Empty(queue.TakeWork(AnalyzerWorkType.Foreground)); }
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); }
public void WhenBackgroundWorkIsAdded_DontWaitIt() { var queue = new AnalyzerWorkQueue(new LoggerFactory(), timeoutForPendingWorkMs: 10 * 1000); var document = CreateTestDocumentId(); queue.PutWork(new[] { document }, AnalyzerWorkType.Background); Assert.True(queue.WaitForegroundWorkComplete().IsCompleted); }
private async Task <ImmutableArray <DocumentDiagnostics> > GetDiagnosticsByDocument(ImmutableArray <Document> documents, bool waitForDocuments) { if (documents.IsDefaultOrEmpty) { return(ImmutableArray <DocumentDiagnostics> .Empty); } ImmutableArray <DocumentDiagnostics> .Builder resultsBuilder = ImmutableArray.CreateBuilder <DocumentDiagnostics>(documents.Length); resultsBuilder.Count = documents.Length; bool foundAll = true; for (int i = 0; i < documents.Length; i++) { if (_currentDiagnosticResultLookup.TryGetValue(documents[i], out var diagnostics)) { resultsBuilder[i] = diagnostics; } else { _workQueue.QueueDocumentForeground(documents[i]); foundAll = false; } } if (foundAll) { return(resultsBuilder.MoveToImmutable()); } await _workQueue.WaitForegroundWorkComplete(); for (int i = 0; i < documents.Length; i++) { if (_currentDiagnosticResultLookup.TryGetValue(documents[i], out var diagnostics)) { resultsBuilder[i] = diagnostics; } else { Debug.Fail("Should have diagnostics after waiting for work"); resultsBuilder[i] = new DocumentDiagnostics(documents[i], ImmutableArray <Diagnostic> .Empty); } } return(resultsBuilder.MoveToImmutable()); }
private async Task <ImmutableArray <DocumentDiagnostics> > GetDiagnosticsByDocumentIds(ImmutableArray <DocumentId> documentIds, bool waitForDocuments) { if (waitForDocuments) { foreach (var documentId in documentIds) { _workQueue.TryPromote(documentId); } await _workQueue.WaitForegroundWorkComplete(); } return(documentIds .Where(x => _currentDiagnosticResultLookup.ContainsKey(x)) .Select(x => _currentDiagnosticResultLookup[x]) .ToImmutableArray()); }
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); }