/// <summary> /// Performs analysis of the document. Returns document global scope /// with declared variables and inner scopes. Does not analyze chain /// of dependencies, it is intended for the single file analysis. /// </summary> private void Analyze(IDependencyChainNode <PythonAnalyzerEntry> node, AsyncCountdownEvent ace, Stopwatch stopWatch) { try { var entry = node.Value; if (!CanUpdateAnalysis(entry, node, _walker.Version, out var module, out var ast, out var currentAnalysis)) { return; } var startTime = stopWatch.Elapsed; AnalyzeEntry(node, entry, module, ast, _walker.Version); LogCompleted(node, module, stopWatch, startTime); } catch (OperationCanceledException oce) { node.Value.TryCancel(oce, _walker.Version); LogCanceled(node.Value.Module); } catch (Exception exception) { node.Value.TrySetException(exception, _walker.Version); node.MarkWalked(); LogException(node.Value.Module, exception); } finally { node.MoveNext(); lock (_syncObj) { if (!_isCanceled) { _progress.ReportRemaining(_walker.Remaining); } _runningTasks--; ace?.Signal(); } } }
/// <summary> /// Performs analysis of the document. Returns document global scope /// with declared variables and inner scopes. Does not analyze chain /// of dependencies, it is intended for the single file analysis. /// </summary> private void Analyze(IDependencyChainNode <PythonAnalyzerEntry> node, AsyncCountdownEvent ace, Stopwatch stopWatch) { try { var entry = node.Value; if (!entry.CanUpdateAnalysis(_walker.Version, out var module, out var ast, out var currentAnalysis)) { if (IsAnalyzedLibraryInLoop(node, currentAnalysis)) { return; } else if (ast == default) { if (currentAnalysis == default) { // Entry doesn't have ast yet. There should be at least one more session. Cancel(); } else { Debug.Fail($"Library module {module.Name} of type {module.ModuleType} has been analyzed already!"); } } _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) canceled."); return; } var startTime = stopWatch.Elapsed; AnalyzeEntry(node, entry, module, ast, _walker.Version); LogCompleted(node, module, stopWatch, startTime); } catch (OperationCanceledException oce) { node.Value.TryCancel(oce, _walker.Version); LogCanceled(node.Value.Module); } catch (Exception exception) { node.Value.TrySetException(exception, _walker.Version); node.MarkWalked(); LogException(node.Value.Module, exception); } finally { node.MoveNext(); bool isCanceled; lock (_syncObj) { isCanceled = _isCanceled; } if (!isCanceled) { _progress.ReportRemaining(_walker.Remaining); } Interlocked.Decrement(ref _runningTasks); ace?.Signal(); } }
public void ItCompletesTheTaskWhenSignalIsCalledSampleTimes() { var asyncACE = new AsyncCountdownEvent(SampleTimes); var task = asyncACE.WaitAsync(); for (int i = 0; i < SampleTimes; i++) { asyncACE.Signal(); } task.Wait(TimeSpan.FromSeconds(1)); Assert.IsTrue(task.IsCompleted); }
private void Analyze(IDependencyChainNode node, AsyncCountdownEvent ace, Stopwatch stopWatch) { var loopAnalysis = false; try { switch (node) { case IDependencyChainSingleNode <PythonAnalyzerEntry> single: try { Analyze(single, stopWatch); } catch (OperationCanceledException oce) { single.Value.TryCancel(oce, _walker.Version); LogCanceled(single.Value.Module); } catch (Exception exception) { single.Value.TrySetException(exception, _walker.Version); node.MarkWalked(); LogException(single.Value, exception); } break; case IDependencyChainLoopNode <PythonAnalyzerEntry> loop: try { loopAnalysis = true; AnalyzeLoop(loop, stopWatch); } catch (OperationCanceledException) { //loop.Value.TryCancel(oce, _walker.Version); //LogCanceled(single.Value.Module); } catch (Exception exception) { //loop.Value.TrySetException(exception, _walker.Version); node.MarkWalked(); LogException(loop, exception); } break; } } finally { node.MoveNext(); bool isCanceled; lock (_syncObj) { isCanceled = _isCanceled; } if (!isCanceled || loopAnalysis) { _progress.ReportRemaining(_walker.Remaining); } Interlocked.Decrement(ref _runningTasks); ace?.Signal(); } }
public async Task DataflowPipeBulkInsertBlockCoreAsync(AsyncCountdownEvent signals, int index, int orderCount) { #region Block Method (int blockCount, int minPerBlock, int maxPerBlock)blockBascInfo = BlockHelper.GetBasciBlockInfo(orderCount); int[] blockInfos = BlockHelper.GetBlockInfo(messageCount: orderCount, blockCount: blockBascInfo.blockCount, minPerBlock: blockBascInfo.minPerBlock, maxPerBlock: blockBascInfo.maxPerBlock); #endregion int boundedCapacity = blockInfos.Sum(b => b); Debug.Assert(orderCount == boundedCapacity); var logger = _loggerFactory.CreateLogger($"DataflowPipeBulkInserter-{index}"); try { var contosoDataSourceFactory = this.ServiceProvider.GetRequiredService <IDataSourceFactory <IContosoDataSource> >(); var orderDataSource = contosoDataSourceFactory.Current.OrderDataSource; var transportTimeWatcher = Stopwatch.StartNew(); TimeSpan totalTransportTime = TimeSpan.Zero; var executionTimeWatcher = Stopwatch.StartNew(); logger.LogInformation($"----begin dataflow pipe bulk insert {orderCount} orders,now:{DateTime.Now.TimeOfDay}----"); int start = 0; for (int i = 0; i < blockInfos.Count(); i++) { int insertOrderCount = blockInfos[i]; var orders = OrderJsonProvider.CreateOrders(start, insertOrderCount); start += insertOrderCount; transportTimeWatcher.Restart(); var dbOrders = await orderDataSource.DataflowPipeBulkInsertOrdersAsync(orders); totalTransportTime += transportTimeWatcher.Elapsed; transportTimeWatcher.Reset(); //if (dbOrders?.Count() > 0) //{ // await ProcessDataflowPipeOrdersAsync(dbOrders); //} } logger .LogInformation($"----dataflow pipe bulk insert {orderCount} orders,cost time:\"{executionTimeWatcher.Elapsed}\",transport time:{ totalTransportTime },count/time(sec):{Math.Ceiling(orderCount / totalTransportTime.TotalSeconds)},now:\"{DateTime.Now.TimeOfDay}\"----"); signals?.Signal(); } catch (Exception ex) { logger.LogError($"Error while dataflow pipe bulk insert orders of {nameof(DataflowPipeBulkInsertLoopCoreAsync)}: {ex.Message}"); } }
/// <summary> /// Performs analysis of the document. Returns document global scope /// with declared variables and inner scopes. Does not analyze chain /// of dependencies, it is intended for the single file analysis. /// </summary> private void Analyze(IDependencyChainNode <PythonAnalyzerEntry> node, AsyncCountdownEvent ace, Stopwatch stopWatch) { IPythonModule module; try { ace?.AddOne(); var entry = node.Value; if (!entry.IsValidVersion(_walker.Version, out module, out var ast)) { if (ast == null) { // Entry doesn't have ast yet. There should be at least one more session. Cancel(); } _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) canceled."); node.Skip(); return; } var startTime = stopWatch.Elapsed; AnalyzeEntry(entry, module, ast, _walker.Version); node.Commit(); _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) completed in {(stopWatch.Elapsed - startTime).TotalMilliseconds} ms."); } catch (OperationCanceledException oce) { node.Value.TryCancel(oce, _walker.Version); node.Skip(); module = node.Value.Module; _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) canceled."); } catch (Exception exception) { module = node.Value.Module; node.Value.TrySetException(exception, _walker.Version); node.Commit(); _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) failed. Exception message: {exception.Message}."); } finally { bool isCanceled; lock (_syncObj) { isCanceled = _isCanceled; } if (!isCanceled) { _progress.ReportRemaining(_walker.Remaining); } Interlocked.Decrement(ref _runningTasks); ace?.Signal(); } }
public async Task DataflowBulkInsertBlockRetryTasksCoreAsync(AsyncCountdownEvent signals, int index, int count, int orderCount) { var logger = _loggerFactory.CreateLogger($"DataflowBulkInserter-TaskCount:{index}"); int totalOrderCount = count * orderCount; try { var dataflowBulkInserter = this.ServiceProvider.GetRequiredService<IDataflowBulkInserter<OrderDto, OrderDto>>(); var contosoDataSourceFactory = this.ServiceProvider.GetRequiredService<IDataSourceFactory<IContosoDataSource>>(); var orderDataSource = contosoDataSourceFactory.Current.OrderDataSource; // await Task.Delay(TimeSpan.FromMilliseconds(2000)); var transportTimeWatcher = Stopwatch.StartNew(); TimeSpan totalTransportTime = TimeSpan.Zero; var executionTimeWatcher = Stopwatch.StartNew(); // logger.LogInformation($"----begin dataflow bulk insert { totalOrderCount} orders,now:{DateTime.Now.TimeOfDay}----"); int start = 0; for (int i = 0; i < count; i++) { var orders = OrderJsonProvider.CreateOrders(start, orderCount); start += orderCount; transportTimeWatcher.Restart(); var dbOrders = await orderDataSource.DataflowBulkInsertOrdersAsync(orders); totalTransportTime += transportTimeWatcher.Elapsed; transportTimeWatcher.Reset(); if (dbOrders?.Count() > 0) { await ProcessDataflowOrdersAsync(dbOrders); } } //logger // .LogInformation($"----dataflow bulk insert {totalOrderCount} orders,cost time:\"{executionTimeWatcher.Elapsed}\",transport time:{ totalTransportTime },count/time(sec):{Math.Ceiling(totalOrderCount / totalTransportTime.TotalSeconds)},now:\"{DateTime.Now.TimeOfDay}\"----"); signals?.Signal(); } catch (Exception ex) { logger.LogError($"Error while dataflow bulk insert orders of {nameof(DataflowBulkInsertBlockRetryTasksCoreAsync)}: {ex.Message}"); } }
/// <summary> /// Performs analysis of the document. Returns document global scope /// with declared variables and inner scopes. Does not analyze chain /// of dependencies, it is intended for the single file analysis. /// </summary> private void Analyze(IDependencyChainNode <PythonAnalyzerEntry> node, AsyncCountdownEvent ace, Stopwatch stopWatch) { try { ace?.AddOne(); var entry = node.Value; if (!entry.IsValidVersion(_walker.Version, out var module, out var ast)) { if (ast == null) { // Entry doesn't have ast yet. There should be at least one more session. Cancel(); } _log?.Log(TraceEventType.Verbose, $"Analysis of {module.Name}({module.ModuleType}) canceled."); node.Skip(); return; } var startTime = stopWatch.Elapsed; AnalyzeEntry(entry, module, _walker.Version, node.IsComplete); node.Commit(); ActivityTracker.OnModuleAnalysisComplete(node.Value.Module.FilePath); LogCompleted(module, stopWatch, startTime); } catch (OperationCanceledException oce) { node.Value.TryCancel(oce, _walker.Version); node.Skip(); LogCanceled(node.Value.Module); } catch (Exception exception) { node.Value.TrySetException(exception, _walker.Version); node.Commit(); LogException(node.Value.Module, exception); } finally { bool isCanceled; lock (_syncObj) { isCanceled = _isCanceled; } if (!isCanceled) { _progress.ReportRemaining(_walker.Remaining); } Interlocked.Decrement(ref _runningTasks); ace?.Signal(); } }
public async Task PipeBulkInsertLoopCoreAsync(AsyncCountdownEvent signals, int index, int count, int orderCount) { var logger = _loggerFactory.CreateLogger($"PipeBulkInserter-{index}"); try { var contosoDataSourceFactory = this.ServiceProvider.GetRequiredService <IDataSourceFactory <IContosoDataSource> >(); var orderDataSource = contosoDataSourceFactory.Current.OrderDataSource; var transportTimeWatcher = Stopwatch.StartNew(); TimeSpan totalTransportTime = TimeSpan.Zero; var executionTimeWatcher = Stopwatch.StartNew(); logger.LogInformation($"----begin pipe bulk insert {orderCount} orders,now:{DateTime.Now.TimeOfDay}----"); int start = 0; for (int i = 0; i < count; i++) { var orders = OrderJsonProvider.CreateOrders(start, orderCount); start += orderCount; transportTimeWatcher.Restart(); var dbOrders = await orderDataSource.PipeBulkInsertOrdersAsync(orders); totalTransportTime += transportTimeWatcher.Elapsed; transportTimeWatcher.Reset(); //if (dbOrders?.Count() > 0) //{ // await ProcessPipeOrdersAsync(dbOrders); //} } logger .LogInformation($"----pipe bulk insert {orderCount} orders,cost time:\"{executionTimeWatcher.Elapsed}\",transport time:{ totalTransportTime },count/time(sec):{Math.Ceiling(orderCount / totalTransportTime.TotalSeconds)},now:\"{DateTime.Now.TimeOfDay}\"----"); signals?.Signal(); } catch (Exception ex) { logger.LogError($"Error while pipe bulk insert orders of {nameof(PipeBulkInsertLoopCoreAsync)}: {ex.Message}"); } }
public void RegisterCallBackOnDataflowBulkInsert(IDataflowBulkInserter <OrderDto, OrderDto> sender, ILogger logger, AsyncCountdownEvent signals = null) { sender.OnInsertCallBack = async(context) => { if (context.Exception != null) { logger.LogError($"exception: {context.Exception} when send {context.MessageConunt} messages"); } else if (context.ExecutionTime != TimeSpan.Zero) { using (await _mutex.LockAsync()) { _durationManage.MaxTime = _durationManage.GetMaxTimeValue(_durationManage.MaxTime, context.ExecutionTime); _durationManage.TotalTime += context.ExecutionTime; _durationManage.TotalCount += context.MessageConunt; } logger .LogInformation($"TotalCount={ _durationManage.TotalCount},ExecutionTime={context.ExecutionTime},ThreadId={Thread.CurrentThread.ManagedThreadId},OrderCount=\"{context.MessageConunt}\""); } signals?.Signal(); }; }
public void SignalThrowsOnError() { var evt = new AsyncCountdownEvent(0); Assert.Throws <InvalidOperationException>(() => evt.Signal()); }
public async Task ProcessCrawlingQueueAsync(CrawlingQueue crawlingQueue) { _crawlingParameters.CancellationTokenSource.Token.Register(() => crawlingQueue.QueueCancellationTokenSource.Cancel() ); var tasksLock = new System.Threading.ReaderWriterLockSlim(); var tasks = new HashSet <Task>(); var queueItemsProcessingSemaphore = new SemaphoreSlim(crawlingQueue.CrawlingConfiguration.MaxSimmultaneousQueueItemsProcessed / 2, crawlingQueue.CrawlingConfiguration.MaxSimmultaneousQueueItemsProcessed); while (await queueItemsProcessingSemaphore.WaitAsync(crawlingQueue.CrawlingConfiguration.MaxTimeToProcessOneQueueItem)) { if (crawlingQueue.QueueCancellationTokenSource.IsCancellationRequested) { await Task.WhenAll(tasks.ToArray()); // TODO: Move remaining items from local queue to the distributed queue // TODO: Figure out how to filter out duplicates from the queue? Or should we? // We will probably have to resort to known urls-based duplicates check // Because otherwise we will drown in failing sql queries on multiplie machines Trace.TraceWarning("ProcessCrawlingQueueAsync: Queue cancellation requested. Preventing dequeing of new elements. Processing will be shut down after currently executing items are complete."); break; } var queueItem = await crawlingQueue.DequeueAsync(); if (queueItem == null) // Both Local and Proxy queues are depleted { // NOTE: If Queue is depleted, we must wait until all running tasks are executed, because they might add new items to queue await Task.WhenAll(tasks.ToArray()); // wait for all queue proxies to complete fetching items // TODO: consider locking (multithreading scenario) var queueProxiesPending = crawlingQueue.QueueProxies.Where(queueProxy => queueProxy.IsPending()).ToArray(); if (queueProxiesPending.Length > 0) { continue; } if (crawlingQueue.LocalQueue.Count > 0) { continue; } break; } if (!await _crawlingEventInterceptorManager.OnAfterDequeueAsync(queueItem)) { // If interceptor returns false, means it's an instruction to ignore this item; continue; } tasksLock.EnterWriteLock(); queueItem.ChangeStatus(CrawlingQueueItem.CrawlingStatuses.Downloading); tasks.Add(System.Threading.Tasks.TaskExtensions.Unwrap( CrawlAsync(queueItem.ResourceLink) .ContinueWith(async task => { tasksLock.EnterWriteLock(); tasks.Remove(task); // to avoid infinite bloating of the collection tasksLock.ExitWriteLock(); try { queueItem.ChangeStatus(CrawlingQueueItem.CrawlingStatuses.Downloaded); if (task.Status == TaskStatus.RanToCompletion) { var resourceContentUnits = task.Result; var httpResultUnit = resourceContentUnits.OfType <HttpResultUnit>().Single(); queueItem.ChangeStatus(CrawlingQueueItem.CrawlingStatuses.Processing); var resourceContentUnitsProcessingCountdown = new AsyncCountdownEvent(resourceContentUnits.Count); // Process resource content units extracted from Response foreach (var resourceContentUnit in resourceContentUnits) { switch (resourceContentUnit) { case ExtractedLinksUnit extractedLinksUnit: if (extractedLinksUnit.ExtractedLinks.Count > 0) { var linksProcessingCountdown = new AsyncCountdownEvent(extractedLinksUnit.ExtractedLinks.Count); foreach (var extractedLink in extractedLinksUnit.ExtractedLinks) { var crawlingQueueItem = new CrawlingQueueItem(extractedLink); // Do not enqueue item if prevented by any interceptor if (!await _crawlingEventInterceptorManager.OnBeforeEnqueueAsync(crawlingQueueItem)) { continue; } crawlingQueueItem.ProcessingCompleted += () => linksProcessingCountdown.AddCount(1) ; crawlingQueue.Enqueue(crawlingQueueItem); } // Wait while all links are processed before releasing the content units semaphore and set Status = Processed for parent linksProcessingCountdown.WaitAsync() .ContinueWith(linksProcessingTask => resourceContentUnitsProcessingCountdown.AddCount(1) ); } else { resourceContentUnitsProcessingCountdown.AddCount(1); } // Set Processed status when all extracted links are processed break; case ExtractedDataUnit extractedDataUnit: if (!await _crawlingEventInterceptorManager.OnDataDocumentDownloadedAsync( queueItem.ResourceLink, // May be a DocumentLink, or a FrameLink. Not quite intuitive and probably requires redesign. extractedDataUnit, httpResultUnit )) { // If any of interceptors failed to process the download result, // AND failed to store download result for later processing // we must re-enqueue the item, in order to ensure the results are not lost for good // We ignore the item and log the error. Chances are we couldn't process the item for a reason. And repeating would just make it stuck infinitely (re-downloading and re-processing) // (WAS) we must re-enqueue the item, in order to ensure the results are not lost for good //crawlingQueue.EnqueueAsync(queueItem); } resourceContentUnitsProcessingCountdown.Signal(); break; case DownloadedFilesUnit downloadedFileUnit: // If download file is a result of redirection, // we must either explicitly declare that we're expecting a file, or throw a processing exception var fileLink = queueItem.ResourceLink as FileLink; if (fileLink == null) { Trace.TraceError($"ProcessCrawlingQueueAsync: Downloaded file unit. Resource link is of type {queueItem.ResourceLink.GetType().Name}, expecting FileLink. Preventing processing."); break; } if (!await _crawlingEventInterceptorManager.OnFileDownloadedAsync( fileLink, downloadedFileUnit, httpResultUnit )) { // If any of interceptors failed to process the download result, // AND failed to store download result for later processing.... // We ignore the item and log the error. Chances are we couldn't process the item for a reason. And repeating would just make it stuck infinitely (re-downloading and re-processing) // (WAS) we must re-enqueue the item, in order to ensure the results are not lost for good //crawlingQueue.EnqueueAsync(queueItem); } resourceContentUnitsProcessingCountdown.Signal(); break; case HttpResultUnit httpResultUnitStub: // TODO: Determine what we should do if HTTP download failed. Either re-enqueue or ignore, or alert/do something else switch (httpResultUnitStub.HttpStatus) { //case HttpStatusCode.InternalServerError: // it's likely to repeat within the same run case HttpStatusCode.GatewayTimeout: case HttpStatusCode.RequestTimeout: queueItem.ChangeStatus(CrawlingQueueItem.CrawlingStatuses.NotLinked); crawlingQueue.Enqueue(queueItem); // Trying to recrawl item if it failed for some intermitent reason break; default: // We need to invoke ProcessingCompleted only after Data and Links extracted are really processed. //queueItem.ChangeStatus(CrawlingQueueItem.CrawlingStatuses.ProcessingCompleted); break; } resourceContentUnitsProcessingCountdown.Signal(); break; default: throw new NotSupportedException(); } } // Do not actually wait for related resources processing completion. // Those might be extracted links or files. No need to hold queue resources while linked units are downloaded // Set Processed status after all content units were registered and interceptors triggered await resourceContentUnitsProcessingCountdown.WaitAsync() .ContinueWith(resourceContentUnitsProcessingTask => queueItem.ChangeStatus(CrawlingQueueItem.CrawlingStatuses.Processed) ); } else { Trace.TraceError("CrawlAsync: Failed for queue item {0} with exception [{1}]", queueItem.ResourceLink, task.Exception); } } finally { queueItemsProcessingSemaphore.Release(); } }) ) ); tasksLock.ExitWriteLock(); } await Task.WhenAll(tasks.ToArray()); }
public async Task CanReindexVersionedIndexWithDeletedDocsAsync() { var version1Index = new VersionedEmployeeIndex(_configuration, 1); await version1Index.DeleteAsync(); var version2Index = new VersionedEmployeeIndex(_configuration, 2); await version2Index.DeleteAsync(); using (new DisposableAction(() => version1Index.DeleteAsync().GetAwaiter().GetResult())) { await version1Index.ConfigureAsync(); Assert.True((await _client.Indices.ExistsAsync(version1Index.VersionedName)).Exists); IEmployeeRepository repository = new EmployeeRepository(_configuration); var employee = await repository.AddAsync(EmployeeGenerator.Default, o => o.ImmediateConsistency()); Assert.NotNull(employee?.Id); using (new DisposableAction(() => version2Index.DeleteAsync().GetAwaiter().GetResult())) { await version2Index.ConfigureAsync(); Assert.True((await _client.Indices.ExistsAsync(version2Index.VersionedName)).Exists); Assert.Equal(1, await version2Index.GetCurrentVersionAsync()); // alias should still point to the old version until reindex var aliasResponse = await _client.Indices.GetAliasAsync(version2Index.Name); _logger.LogRequest(aliasResponse); Assert.True(aliasResponse.IsValid); Assert.Equal(1, aliasResponse.Indices.Count); Assert.Equal(version1Index.VersionedName, aliasResponse.Indices.First().Key); var countdown = new AsyncCountdownEvent(1); var reindexTask = version2Index.ReindexAsync(async(progress, message) => { _logger.LogInformation($"Reindex Progress {progress}%: {message}"); if (progress == 91) { countdown.Signal(); await Task.Delay(1000); } }); // Wait until the first reindex pass is done. await countdown.WaitAsync(); Assert.Equal(1, await version1Index.GetCurrentVersionAsync()); await repository.RemoveAllAsync(o => o.ImmediateConsistency()); // Resume after everythings been indexed. await reindexTask; aliasResponse = await _client.Indices.GetAliasAsync(version2Index.Name); _logger.LogRequest(aliasResponse); Assert.True(aliasResponse.IsValid, aliasResponse.GetErrorMessage()); Assert.Equal(1, aliasResponse.Indices.Count); Assert.Equal(version2Index.VersionedName, aliasResponse.Indices.First().Key); Assert.Equal(2, await version1Index.GetCurrentVersionAsync()); Assert.Equal(2, await version2Index.GetCurrentVersionAsync()); var countResponse = await _client.CountAsync <Employee>(d => d.Index(version1Index.VersionedName)); _logger.LogRequest(countResponse); Assert.True(countResponse.ApiCall.HttpStatusCode == 404, countResponse.GetErrorMessage()); Assert.Equal(0, countResponse.Count); countResponse = await _client.CountAsync <Employee>(d => d.Index(version2Index.VersionedName)); _logger.LogRequest(countResponse); Assert.True(countResponse.IsValid, countResponse.GetErrorMessage()); Assert.Equal(1, countResponse.Count); Assert.Equal(employee, await repository.GetByIdAsync(employee.Id)); Assert.False((await _client.Indices.ExistsAsync(version1Index.VersionedName)).Exists); } } }
public async Task CanIncrementUsageAsync() { var cache = IoC.GetInstance <ICacheClient>() as InMemoryCacheClient; Assert.NotNull(cache); await cache.RemoveAllAsync(); var countdown = new AsyncCountdownEvent(2); var messagePublisher = IoC.GetInstance <IMessagePublisher>() as InMemoryMessageBus; Assert.NotNull(messagePublisher); messagePublisher.Subscribe <PlanOverage>(po => { _logger.Info($"Plan Overage for {po.OrganizationId} (Hourly: {po.IsHourly})"); countdown.Signal(); }); var o = await _repository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = BillingManager.FreePlan.Id }); await _client.RefreshAsync(); Assert.InRange(o.GetHourlyEventLimit(), 1, 750); int totalToIncrement = o.GetHourlyEventLimit() - 1; Assert.False(await _repository.IncrementUsageAsync(o.Id, false, totalToIncrement)); await _client.RefreshAsync(); o = await _repository.GetByIdAsync(o.Id); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(2, countdown.CurrentCount); Assert.Equal(totalToIncrement, await cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(0, await cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(0, await cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.True(await _repository.IncrementUsageAsync(o.Id, false, 2)); await _client.RefreshAsync(); o = await _repository.GetByIdAsync(o.Id); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); Assert.Equal(totalToIncrement + 2, await cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement + 2, await cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(1, await cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(1, await cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); o = await _repository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = BillingManager.FreePlan.Id }); await _client.RefreshAsync(); totalToIncrement = o.GetHourlyEventLimit() + 20; Assert.True(await _repository.IncrementUsageAsync(o.Id, false, totalToIncrement)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(0, countdown.CurrentCount); Assert.Equal(totalToIncrement, await cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(20, await cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(20, await cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); }
public async Task Any_given_lease_is_never_handed_out_to_more_than_one_handler_at_a_time() { var random = new Random(); var currentlyGranted = new HashSet<string>(); var everGranted = new HashSet<string>(); var leasedConcurrently = ""; var distributor = CreateDistributor(waitInterval: TimeSpan.FromSeconds(5)).Trace(); var countDown = new AsyncCountdownEvent(10); distributor.OnReceive(async lease => { lock (currentlyGranted) { if (currentlyGranted.Contains(lease.LeasableResource.Name)) { leasedConcurrently = lease.LeasableResource.Name; } currentlyGranted.Add(lease.LeasableResource.Name); everGranted.Add(lease.LeasableResource.Name); } await Task.Delay((int) (1000*random.NextDouble())); lock (currentlyGranted) { currentlyGranted.Remove(lease.LeasableResource.Name); } countDown.Signal(); }); Enumerable.Range(1, 10).ToList().ForEach(_ => { distributor.Distribute(1); }); await countDown.WaitAsync().Timeout(); leasedConcurrently.Should().BeEmpty(); everGranted.Count.Should().Be(10); }
/// <summary> /// Registers a task with the ASP.NET runtime. /// </summary> /// <param name="task">The task to register.</param> private void Register(Task task) { count.AddCount(); task.ContinueWith(_ => count.Signal(), TaskContinuationOptions.ExecuteSynchronously); }
protected async Task CanHaveMultipleQueueInstancesWithLockingImplAsync(CacheLockProvider distributedLock) { var queue = GetQueue(retries: 0, retryDelay: TimeSpan.Zero); if (queue == null) { return; } try { await queue.DeleteQueueAsync(); await AssertEmptyQueueAsync(queue); const int workItemCount = 16; const int workerCount = 4; var countdown = new AsyncCountdownEvent(workItemCount); var info = new WorkInfo(); var workers = new List <IQueue <SimpleWorkItem> > { queue }; try { for (int i = 0; i < workerCount; i++) { var q = GetQueue(retries: 0, retryDelay: TimeSpan.Zero); int instanceCount = i; await q.StartWorkingAsync(async w => { _logger.Info("[{0}] Acquiring distributed lock in work item: {1}", instanceCount, w.Id); var l = await distributedLock.AcquireAsync("test"); Assert.NotNull(l); _logger.Info("[{0}] Acquired distributed lock: {1}", instanceCount, w.Id); SystemClock.Sleep(TimeSpan.FromMilliseconds(50)); await l.ReleaseAsync(); _logger.Info("[{0}] Released distributed lock: {1}", instanceCount, w.Id); await w.CompleteAsync(); info.IncrementCompletedCount(); countdown.Signal(); _logger.Info("[{0}] Signaled countdown: {1}", instanceCount, w.Id); }); workers.Add(q); } await Run.InParallelAsync(workItemCount, async i => { string id = await queue.EnqueueAsync(new SimpleWorkItem { Data = "Hello", Id = i }); _logger.Trace("Enqueued Index: {0} Id: {1}", i, id); }); await countdown.WaitAsync(TimeSpan.FromSeconds(5).ToCancellationToken()); await SystemClock.SleepAsync(50); _logger.Trace("Completed: {0} Abandoned: {1} Error: {2}", info.CompletedCount, info.AbandonCount, info.ErrorCount); _logger.Info("Work Info Stats: Completed: {completed} Abandoned: {abandoned} Error: {errors}", info.CompletedCount, info.AbandonCount, info.ErrorCount); Assert.Equal(workItemCount, info.CompletedCount + info.AbandonCount + info.ErrorCount); // In memory queue doesn't share state. if (queue.GetType() == typeof(InMemoryQueue <SimpleWorkItem>)) { var stats = await queue.GetQueueStatsAsync(); Assert.Equal(info.CompletedCount, stats.Completed); } else { var workerStats = new List <QueueStats>(); for (int i = 0; i < workers.Count; i++) { var stats = await workers[i].GetQueueStatsAsync(); _logger.Info("Worker#{i} Working: {working} Completed: {completed} Abandoned: {abandoned} Error: {errors} Deadletter: {deadletter}", i, stats.Working, stats.Completed, stats.Abandoned, stats.Errors, stats.Deadletter); workerStats.Add(stats); } Assert.Equal(info.CompletedCount, workerStats.Sum(s => s.Completed)); } } finally { foreach (var q in workers) { await CleanupQueueAsync(q); } } } finally { await CleanupQueueAsync(queue); } }
public async Task WatchAllEvents() { AsyncCountdownEvent eventsReceived = new AsyncCountdownEvent(4 /* first line of response is eaten by WatcherDelegatingHandler */); AsyncManualResetEvent serverShutdown = new AsyncManualResetEvent(); var waitForClosed = new AsyncManualResetEvent(false); using (var server = new MockKubeApiServer(testOutput, async httpContext => { await WriteStreamLine(httpContext, MockAddedEventStreamLine); await WriteStreamLine(httpContext, MockDeletedStreamLine); await WriteStreamLine(httpContext, MockModifiedStreamLine); await WriteStreamLine(httpContext, MockErrorStreamLine); // make server alive, cannot set to int.max as of it would block response await serverShutdown.WaitAsync(); return(false); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch : true); var events = new HashSet <WatchEventType>(); var errors = 0; var watcher = listTask.Watch <V1Pod, V1PodList>( (type, item) => { testOutput.WriteLine($"Watcher received '{type}' event."); events.Add(type); eventsReceived.Signal(); }, error => { testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); errors += 1; eventsReceived.Signal(); }, onClosed: waitForClosed.Set ); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for all events / errors to be received." ); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); Assert.Contains(WatchEventType.Modified, events); Assert.Contains(WatchEventType.Error, events); Assert.Equal(0, errors); Assert.True(watcher.Watching); serverShutdown.Set(); await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)); Assert.True(waitForClosed.IsSet); Assert.False(watcher.Watching); } }
public async Task <List <Task> > RunAsync(int numPushers, int numPullers, int numMessagesPerPusher, AsyncCountdownEvent counter, CancellationToken token) { var inUrl = UrlIpc(); var outUrl = UrlIpc(); const int numBrokers = 1; var brokersReady = new AsyncBarrier(numBrokers + 1); var clientsReady = new AsyncBarrier(numPushers + numPullers + numBrokers); var numForwarded = 0; var tasks = new List <Task>(); for (var i = 0; i < numBrokers; ++i) { var task = Task.Run(async() => { var pullSocket = implementation.CreateInSocket(inUrl); var pushSocket = implementation.CreateOutSocket(outUrl); await brokersReady.SignalAndWait(); // Broker is ready await clientsReady.SignalAndWait(); // Wait for clients while (!token.IsCancellationRequested) { var msg = await pullSocket.Receive(token); await pushSocket.Send(msg.Unwrap()); ++numForwarded; } }); tasks.Add(task); } await brokersReady.SignalAndWait(); for (var i = 0; i < numPushers; ++i) { var task = Task.Run(async() => { using (var socket = implementation.Factory.PusherOpen().ThenDial(inUrl).Unwrap()) using (var ctx = socket.CreateAsyncContext(implementation.Factory).Unwrap()) { await clientsReady.SignalAndWait(); // This client ready, wait for rest // Give all receivers a chance to actually start receiving await WaitShort(); for (var m = 0; m < numMessagesPerPusher; ++m) { await ctx.Send(implementation.CreateMessage()); await WaitShort(); } } }); tasks.Add(task); } for (var i = 0; i < numPullers; ++i) { var task = Task.Run(async() => { var pullSocket = implementation.CreateClient(outUrl); await clientsReady.SignalAndWait(); // This client ready, wait for rest while (!token.IsCancellationRequested) { var _ = await pullSocket.Receive(token); counter.Signal(); } }); tasks.Add(task); } return(tasks); }
async Task DoContexts(string url) { const int NumSurveyors = 1; const int NumResponders = 3; var readyToDial = new AsyncBarrier(NumSurveyors + NumResponders); var readyToSend = new AsyncBarrier(NumSurveyors + NumResponders); var numSurveyorReceive = new AsyncCountdownEvent(NumSurveyors); var numResponderReceive = new AsyncCountdownEvent(NumSurveyors); using (var surveySocket = Factory.SurveyorCreate(url, true).Unwrap()) using (var respondSocket = Factory.RespondentCreate(url, false).Unwrap()) { var cts = new CancellationTokenSource(); var tasks = new List <Task>(); for (var i = 0; i < NumSurveyors; ++i) { var task = Task.Run(async() => { using (var ctx = surveySocket.CreateAsyncContext(Factory).Unwrap()) { (ctx as ICtx).Ctx.SetOpt(Native.Defines.NNG_OPT_SURVEYOR_SURVEYTIME, new nng_duration { TimeMs = DefaultTimeoutMs }); await readyToDial.SignalAndWait(); await readyToSend.SignalAndWait(); // Send survey and receive responses var survey = Factory.CreateMessage(); //Assert.Equal(0, survey.Header.Append((uint)(0x8000000 | i))); // Protocol header contains "survey ID" await ctx.Send(survey); while (!cts.IsCancellationRequested) { try { var response = await ctx.Receive(cts.Token); if (numSurveyorReceive.Signal() == 0) { break; } } catch (Exception ex) { Console.Error.WriteLine(ex.ToString()); throw ex; } } } }); tasks.Add(task); } for (var i = 0; i < NumResponders; ++i) { var task = Task.Run(async() => { await readyToDial.SignalAndWait(); using (var ctx = respondSocket.CreateAsyncContext(Factory).Unwrap()) { await readyToSend.SignalAndWait(); try { // Receive survey and send response var survey = await ctx.Receive(cts.Token); (await ctx.Send(survey.Unwrap())).Unwrap(); numResponderReceive.Signal(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); throw ex; } } }); tasks.Add(task); } await Util.CancelAfterAssertwait(tasks, cts); Assert.Equal(0, numSurveyorReceive.Count); Assert.Equal(0, numResponderReceive.Count); } }
async Task DoContexts(string url) { const int NumSurveyors = 1; const int NumResponders = 2; var readyToDial = new AsyncBarrier(NumSurveyors + NumResponders); var readyToSend = new AsyncBarrier(NumSurveyors + NumResponders); var ready = readyToSend.WaitAsync(); var numSurveyorReceive = new AsyncCountdownEvent(NumSurveyors); var numResponderReceive = new AsyncCountdownEvent(NumSurveyors); using (var surveySocket = Factory.SurveyorOpen().ThenListen(url).Unwrap()) using (var respondSocket = Factory.RespondentOpen().ThenDial(url).Unwrap()) { var duration = new nng_duration { TimeMs = DefaultTimeoutMs }; // Send() is not cancelable so need it to timeout surveySocket.SetOpt(nng.Native.Defines.NNG_OPT_SENDTIMEO, new nng_duration { TimeMs = 50 }); surveySocket.SetOpt(nng.Native.Defines.NNG_OPT_RECVTIMEO, nng_duration.Infinite); surveySocket.SetOpt(Native.Defines.NNG_OPT_SURVEYOR_SURVEYTIME, nng_duration.Infinite); respondSocket.SetOpt(nng.Native.Defines.NNG_OPT_SENDTIMEO, new nng_duration { TimeMs = 50 }); var cts = new CancellationTokenSource(); var tasks = new List <Task>(); for (var i = 0; i < NumSurveyors; ++i) { var id = i; var task = Task.Run(async() => { using (var ctx = surveySocket.CreateAsyncContext(Factory).Unwrap()) { ctx.Ctx.SetOpt(Native.Defines.NNG_OPT_RECVTIMEO, nng_duration.Infinite); ctx.Ctx.SetOpt(Native.Defines.NNG_OPT_SURVEYOR_SURVEYTIME, nng_duration.Infinite); await readyToDial.SignalAndWait(); await readyToSend.SignalAndWait(); // Send survey and receive responses var survey = Factory.CreateMessage(); var val = (uint)rng.Next(); survey.Append(val); //Assert.Equal(0, survey.Header.Append((uint)(0x8000000 | i))); // Protocol header contains "survey ID" (await ctx.Send(survey)).Unwrap(); while (!cts.IsCancellationRequested) { try { var response = (await ctx.Receive(cts.Token)).Unwrap(); response.Trim(out uint respVal); Assert.Equal(val, respVal); if (numSurveyorReceive.Signal() == 0) { break; } } catch (Exception ex) { Console.Error.WriteLine(ex.ToString()); throw ex; } } } }); tasks.Add(task); } for (var i = 0; i < NumResponders; ++i) { var id = i; var task = Task.Run(async() => { await readyToDial.SignalAndWait(); using (var ctx = respondSocket.CreateAsyncContext(Factory).Unwrap()) { // Receive survey and send response try { // Receive is async, give it a chance to start before signaling we are ready. // This to avoid race where surveyor sends before it actually starts receiving var recvFuture = ctx.Receive(cts.Token); await WaitShort(); await readyToSend.SignalAndWait(); var survey = (await recvFuture).Unwrap(); await Task.Delay(10); // Make sure surveyor has a chance to start receiving (await ctx.Send(survey)).Unwrap(); numResponderReceive.Signal(); await numSurveyorReceive.WaitAsync(); cts.Cancel(); // Cancel any responders still receiving } catch (Exception ex) { Console.WriteLine(ex.ToString()); throw ex; } } }); tasks.Add(task); } await Task.WhenAny(ready, Task.WhenAll(tasks)); await Util.CancelAfterAssertwait(tasks, cts); Assert.Equal(0, numSurveyorReceive.Count); Assert.Equal(0, numResponderReceive.Count); } }
public Task Invoke(IncomingContext context, Func <Task> next) { countdown.Signal(); return(next()); }
public async Task CanIncrementSuspendedOrganizationUsageAsync() { var messageBus = GetService <IMessageBus>(); var countdown = new AsyncCountdownEvent(2); await messageBus.SubscribeAsync <PlanOverage>(po => { _logger.LogInformation("Plan Overage for {organization} (Hourly: {IsHourly})", po.OrganizationId, po.IsHourly); countdown.Signal(); }); var organization = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = _plans.SmallPlan.Id }, o => o.ImmediateConsistency()); var project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = organization.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, o => o.ImmediateConsistency()); Assert.False(await _usageService.IncrementUsageAsync(organization, project, 5)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(2, countdown.CurrentCount); var organizationUsage = await _usageService.GetUsageAsync(organization); var projectUsage = await _usageService.GetUsageAsync(organization, project); Assert.Equal(5, organizationUsage.HourlyTotal); Assert.Equal(5, projectUsage.HourlyTotal); Assert.Equal(5, organizationUsage.MonthlyTotal); Assert.Equal(5, projectUsage.MonthlyTotal); Assert.Equal(0, organizationUsage.HourlyBlocked); Assert.Equal(0, projectUsage.HourlyBlocked); Assert.Equal(0, organizationUsage.MonthlyBlocked); Assert.Equal(0, projectUsage.MonthlyBlocked); organization.IsSuspended = true; organization.SuspendedByUserId = TestConstants.UserId; organization.SuspensionDate = SystemClock.UtcNow; organization.SuspensionCode = SuspensionCode.Billing; organization = await _organizationRepository.SaveAsync(organization, o => o.ImmediateConsistency()); Assert.True(await _usageService.IncrementUsageAsync(organization, project, 4995)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); organizationUsage = await _usageService.GetUsageAsync(organization); projectUsage = await _usageService.GetUsageAsync(organization, project); Assert.Equal(5000, organizationUsage.HourlyTotal); Assert.Equal(5000, projectUsage.HourlyTotal); Assert.Equal(5000, organizationUsage.MonthlyTotal); Assert.Equal(5000, projectUsage.MonthlyTotal); Assert.Equal(4995, organizationUsage.HourlyBlocked); Assert.Equal(4995, projectUsage.HourlyBlocked); Assert.Equal(4995, organizationUsage.MonthlyBlocked); Assert.Equal(4995, projectUsage.MonthlyBlocked); organization.RemoveSuspension(); organization = await _organizationRepository.SaveAsync(organization, o => o.ImmediateConsistency()); Assert.False(await _usageService.IncrementUsageAsync(organization, project, 1)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); organizationUsage = await _usageService.GetUsageAsync(organization); projectUsage = await _usageService.GetUsageAsync(organization, project); Assert.Equal(5001, organizationUsage.HourlyTotal); Assert.Equal(5001, projectUsage.HourlyTotal); Assert.Equal(5001, organizationUsage.MonthlyTotal); Assert.Equal(5001, projectUsage.MonthlyTotal); Assert.Equal(4995, organizationUsage.HourlyBlocked); Assert.Equal(4995, projectUsage.HourlyBlocked); Assert.Equal(4995, organizationUsage.MonthlyBlocked); Assert.Equal(4995, projectUsage.MonthlyBlocked); }
public async Task CanReindexVersionedIndexWithUpdatedDocsAsync() { var version1Index = new VersionedEmployeeIndex(_configuration, 1); await version1Index.DeleteAsync(); var version2Index = new VersionedEmployeeIndex(_configuration, 2); await version2Index.DeleteAsync(); using (new DisposableAction(() => version1Index.DeleteAsync().GetAwaiter().GetResult())) { await version1Index.ConfigureAsync(); Assert.True(_client.IndexExists(version1Index.VersionedName).Exists); var repository = new EmployeeRepository(version1Index.Employee); var employee = await repository.AddAsync(EmployeeGenerator.Default, o => o.ImmediateConsistency()); Assert.NotNull(employee?.Id); using (new DisposableAction(() => version2Index.DeleteAsync().GetAwaiter().GetResult())) { await version2Index.ConfigureAsync(); Assert.True(_client.IndexExists(version2Index.VersionedName).Exists); Assert.Equal(1, await version2Index.GetCurrentVersionAsync()); // alias should still point to the old version until reindex var aliasResponse = await _client.GetAliasAsync(descriptor => descriptor.Name(version2Index.Name)); Assert.True(aliasResponse.IsValid); Assert.Equal(1, aliasResponse.Indices.Count); Assert.Equal(version1Index.VersionedName, aliasResponse.Indices.First().Key); var countdown = new AsyncCountdownEvent(1); var reindexTask = version2Index.ReindexAsync((progress, message) => { _logger.LogInformation($"Reindex Progress {progress}%: {message}"); if (progress == 91) { countdown.Signal(); SystemClock.Sleep(1000); } return(Task.CompletedTask); }); // Wait until the first reindex pass is done. await countdown.WaitAsync(); Assert.Equal(1, await version1Index.GetCurrentVersionAsync()); await repository.AddAsync(EmployeeGenerator.Generate(createdUtc: SystemClock.UtcNow)); employee.Name = "Updated"; await repository.SaveAsync(employee); // Resume after everythings been indexed. await reindexTask; aliasResponse = await _client.GetAliasAsync(descriptor => descriptor.Name(version2Index.Name)); Assert.True(aliasResponse.IsValid); Assert.Equal(1, aliasResponse.Indices.Count); Assert.Equal(version2Index.VersionedName, aliasResponse.Indices.First().Key); Assert.Equal(2, await version1Index.GetCurrentVersionAsync()); Assert.Equal(2, await version2Index.GetCurrentVersionAsync()); await _client.RefreshAsync(Indices.All); var countResponse = await _client.CountAsync <Employee>(d => d.Index(version2Index.VersionedName)); _logger.LogTrace(countResponse.GetRequest()); Assert.True(countResponse.IsValid); Assert.Equal(2, countResponse.Count); var result = await repository.GetByIdAsync(employee.Id); Assert.Equal(ToJson(employee), ToJson(result)); Assert.False((await _client.IndexExistsAsync(version1Index.VersionedName)).Exists); } } }
public async Task CanIncrementUsageAsync() { var messageBus = GetService <IMessageBus>(); var countdown = new AsyncCountdownEvent(2); await messageBus.SubscribeAsync <PlanOverage>(po => { _logger.LogInformation("Plan Overage for {organization} (Hourly: {IsHourly})", po.OrganizationId, po.IsHourly); countdown.Signal(); }); var organization = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = _plans.SmallPlan.Id }, o => o.ImmediateConsistency()); var project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = organization.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, o => o.ImmediateConsistency()); Assert.InRange(organization.GetHourlyEventLimit(_plans), 1, 750); int totalToIncrement = organization.GetHourlyEventLimit(_plans) - 1; Assert.False(await _usageService.IncrementUsageAsync(organization, project, totalToIncrement)); organization = await _organizationRepository.GetByIdAsync(organization.Id); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(2, countdown.CurrentCount); var organizationUsage = await _usageService.GetUsageAsync(organization); var projectUsage = await _usageService.GetUsageAsync(organization, project); Assert.Equal(totalToIncrement, organizationUsage.HourlyTotal); Assert.Equal(totalToIncrement, projectUsage.HourlyTotal); Assert.Equal(totalToIncrement, organizationUsage.MonthlyTotal); Assert.Equal(totalToIncrement, projectUsage.MonthlyTotal); Assert.Equal(0, organizationUsage.HourlyBlocked); Assert.Equal(0, projectUsage.HourlyBlocked); Assert.Equal(0, organizationUsage.MonthlyBlocked); Assert.Equal(0, projectUsage.MonthlyBlocked); Assert.True(await _usageService.IncrementUsageAsync(organization, project, 2)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); organizationUsage = await _usageService.GetUsageAsync(organization); projectUsage = await _usageService.GetUsageAsync(organization, project); Assert.Equal(totalToIncrement + 2, organizationUsage.HourlyTotal); Assert.Equal(totalToIncrement + 2, projectUsage.HourlyTotal); Assert.Equal(totalToIncrement + 2, organizationUsage.MonthlyTotal); Assert.Equal(totalToIncrement + 2, projectUsage.MonthlyTotal); Assert.Equal(1, organizationUsage.HourlyBlocked); Assert.Equal(1, projectUsage.HourlyBlocked); Assert.Equal(1, organizationUsage.MonthlyBlocked); Assert.Equal(1, projectUsage.MonthlyBlocked); organization = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = _plans.SmallPlan.Id }, o => o.ImmediateConsistency()); project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = organization.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, o => o.ImmediateConsistency()); await _cache.RemoveAllAsync(); totalToIncrement = organization.GetHourlyEventLimit(_plans) + 20; Assert.True(await _usageService.IncrementUsageAsync(organization, project, totalToIncrement)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(0, countdown.CurrentCount); organizationUsage = await _usageService.GetUsageAsync(organization); projectUsage = await _usageService.GetUsageAsync(organization, project); Assert.Equal(totalToIncrement, organizationUsage.HourlyTotal); Assert.Equal(totalToIncrement, projectUsage.HourlyTotal); Assert.Equal(totalToIncrement, organizationUsage.MonthlyTotal); Assert.Equal(totalToIncrement, projectUsage.MonthlyTotal); Assert.Equal(20, organizationUsage.HourlyBlocked); Assert.Equal(20, projectUsage.HourlyBlocked); Assert.Equal(20, organizationUsage.MonthlyBlocked); Assert.Equal(20, projectUsage.MonthlyBlocked); }
public async Task An_interval_can_be_specified_before_which_a_released_lease_will_be_granted_again() { var tally = new ConcurrentDictionary<string, int>(); var distributor = CreateDistributor(waitInterval: TimeSpan.FromMilliseconds(5000)).Trace(); var countdown = new AsyncCountdownEvent(10); distributor.OnReceive(async lease => { tally.AddOrUpdate(lease.LeasableResource.Name, addValueFactory: s => 1, updateValueFactory: (s, v) => v + 1); countdown.Signal(); }); await distributor.Start(); await countdown.WaitAsync().Timeout(); await distributor.Stop(); tally.Count.Should().Be(10); tally.Should().ContainKeys("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"); tally.Should().ContainValues(1, 1, 1, 1, 1, 1, 1, 1, 1, 1); }
public async Task SuriveBadLine() { AsyncCountdownEvent eventsReceived = new AsyncCountdownEvent(5); AsyncManualResetEvent serverShutdown = new AsyncManualResetEvent(); AsyncManualResetEvent connectionClosed = new AsyncManualResetEvent(); using (var server = new MockKubeApiServer( testOutput, async httpContext => { httpContext.Response.StatusCode = (int)HttpStatusCode.OK; httpContext.Response.ContentLength = null; await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); await WriteStreamLine(httpContext, MockBadStreamLine); await WriteStreamLine(httpContext, MockAddedEventStreamLine); await WriteStreamLine(httpContext, MockBadStreamLine); await WriteStreamLine(httpContext, MockModifiedStreamLine); // make server alive, cannot set to int.max as of it would block response await serverShutdown.WaitAsync(); return(false); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch : true); var events = new HashSet <WatchEventType>(); var errors = 0; var watcher = listTask.Watch <V1Pod, V1PodList>( (type, item) => { testOutput.WriteLine($"Watcher received '{type}' event."); events.Add(type); eventsReceived.Signal(); }, error => { testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); errors += 1; eventsReceived.Signal(); }, onClosed: connectionClosed.Set ); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for all events / errors to be received." ); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Modified, events); Assert.Equal(3, errors); Assert.True(watcher.Watching); // Let the server know it can initiate a shut down. serverShutdown.Set(); await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)); Assert.True(connectionClosed.IsSet); } }
public async Task DisposeWatch() { var connectionClosed = new AsyncManualResetEvent(); var eventsReceived = new AsyncCountdownEvent(1); bool serverRunning = true; using (var server = new MockKubeApiServer(testOutput, async httpContext => { await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse); while (serverRunning) { await WriteStreamLine(httpContext, MockAddedEventStreamLine); } return(true); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch : true); var events = new HashSet <WatchEventType>(); var watcher = listTask.Watch <V1Pod, V1PodList>( (type, item) => { events.Add(type); eventsReceived.Signal(); }, onClosed: connectionClosed.Set ); // wait at least an event await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for events." ); Assert.NotEmpty(events); Assert.True(watcher.Watching); watcher.Dispose(); events.Clear(); // Let the server disconnect serverRunning = false; var timeout = Task.Delay(TestTimeout); while (!timeout.IsCompleted && watcher.Watching) { await Task.Yield(); } Assert.Empty(events); Assert.False(watcher.Watching); Assert.True(connectionClosed.IsSet); } }
public async Task DirectWatchEventsWithTimeout() { AsyncCountdownEvent eventsReceived = new AsyncCountdownEvent(4); AsyncManualResetEvent serverShutdown = new AsyncManualResetEvent(); using (var server = new MockKubeApiServer(testOutput, async httpContext => { await Task.Delay(TimeSpan.FromSeconds(120)); // The default timeout is 100 seconds await WriteStreamLine(httpContext, MockAddedEventStreamLine); await WriteStreamLine(httpContext, MockDeletedStreamLine); await WriteStreamLine(httpContext, MockModifiedStreamLine); await WriteStreamLine(httpContext, MockErrorStreamLine); // make server alive, cannot set to int.max as of it would block response await serverShutdown.WaitAsync(); return(false); })) { var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var events = new HashSet <WatchEventType>(); var errors = 0; var watcher = await client.WatchNamespacedPodAsync( name : "myPod", @namespace : "default", onEvent : (type, item) => { testOutput.WriteLine($"Watcher received '{type}' event."); events.Add(type); eventsReceived.Signal(); }, onError : error => { testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); errors += 1; eventsReceived.Signal(); } ); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, "Timed out waiting for all events / errors to be received." ); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); Assert.Contains(WatchEventType.Modified, events); Assert.Contains(WatchEventType.Error, events); Assert.Equal(0, errors); Assert.True(watcher.Watching); serverShutdown.Set(); } }
public async Task CanIncrementSuspendedOrganizationUsageAsync() { var messageBus = GetService <IMessageBus>(); var countdown = new AsyncCountdownEvent(2); await messageBus.SubscribeAsync <PlanOverage>(po => { _logger.Info($"Plan Overage for {po.OrganizationId} (Hourly: {po.IsHourly}"); countdown.Signal(); }); var o = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = BillingManager.SmallPlan.Id }, opt => opt.Cache()); var project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = o.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, opt => opt.Cache()); Assert.False(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, 5)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(2, countdown.CurrentCount); Assert.Equal(5, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(5, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(5, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(5, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); o.IsSuspended = true; o.SuspendedByUserId = TestConstants.UserId; o.SuspensionDate = SystemClock.UtcNow; o.SuspensionCode = SuspensionCode.Billing; o = await _organizationRepository.SaveAsync(o, opt => opt.Cache()); Assert.True(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, 4995)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); Assert.Equal(5000, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(5000, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(5000, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(5000, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); o.RemoveSuspension(); o = await _organizationRepository.SaveAsync(o, opt => opt.Cache()); Assert.False(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, 1)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); Assert.Equal(5001, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(5001, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(5001, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(5001, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(4995, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); }
public override Task Invoke(IncomingLogicalContext context, Func <Task> next) { context.Message.Instance.ToString().Output(); countdown.Signal(); return(next()); }
public async Task CanIncrementUsageAsync() { var messageBus = GetService <IMessageBus>(); var countdown = new AsyncCountdownEvent(2); await messageBus.SubscribeAsync <PlanOverage>(po => { _logger.Info($"Plan Overage for {po.OrganizationId} (Hourly: {po.IsHourly})"); countdown.Signal(); }); var o = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = BillingManager.SmallPlan.Id }); var project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = o.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, opt => opt.Cache()); await _configuration.Client.RefreshAsync(Indices.All); Assert.InRange(o.GetHourlyEventLimit(), 1, 750); int totalToIncrement = o.GetHourlyEventLimit() - 1; Assert.False(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, totalToIncrement)); await _configuration.Client.RefreshAsync(Indices.All); o = await _organizationRepository.GetByIdAsync(o.Id); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(2, countdown.CurrentCount); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(0, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.True(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, 2)); await _configuration.Client.RefreshAsync(Indices.All); o = await _organizationRepository.GetByIdAsync(o.Id); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(1, countdown.CurrentCount); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement + 2, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(1, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); o = await _organizationRepository.AddAsync(new Organization { Name = "Test", MaxEventsPerMonth = 750, PlanId = BillingManager.SmallPlan.Id }); project = await _projectRepository.AddAsync(new Project { Name = "Test", OrganizationId = o.Id, NextSummaryEndOfDayTicks = SystemClock.UtcNow.Ticks }, opt => opt.Cache()); await _configuration.Client.RefreshAsync(Indices.All); await _cache.RemoveAllAsync(); totalToIncrement = o.GetHourlyEventLimit() + 20; Assert.True(await _usageService.IncrementUsageAsync(o.Id, project.Id, false, totalToIncrement)); await countdown.WaitAsync(TimeSpan.FromMilliseconds(150)); Assert.Equal(0, countdown.CurrentCount); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetHourlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id), 0)); Assert.Equal(totalToIncrement, await _cache.GetAsync <long>(GetMonthlyTotalCacheKey(o.Id, project.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetHourlyBlockedCacheKey(o.Id, project.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id), 0)); Assert.Equal(20, await _cache.GetAsync <long>(GetMonthlyBlockedCacheKey(o.Id, project.Id), 0)); }
public virtual async Task CanReceiveMessagesConcurrentlyAsync() { const int iterations = 100; var messageBus = GetMessageBus(); if (messageBus == null) { return; } var messageBuses = new List <IMessageBus>(10); try { var countdown = new AsyncCountdownEvent(iterations * 10); await Run.InParallelAsync(10, async i => { var bus = GetMessageBus(); await bus.SubscribeAsync <SimpleMessageA>(msg => { Assert.Equal("Hello", msg.Data); countdown.Signal(); }); messageBuses.Add(bus); }); var subscribe = Run.InParallelAsync(iterations, i => { #pragma warning disable AsyncFixer02 // Long running or blocking operations under an async method SystemClock.Sleep(RandomData.GetInt(0, 10)); #pragma warning restore AsyncFixer02 // Long running or blocking operations under an async method return(messageBuses.Random().SubscribeAsync <NeverPublishedMessage>(msg => Task.CompletedTask)); }); var publish = Run.InParallelAsync(iterations + 3, i => { switch (i) { case 1: return(messageBus.PublishAsync(new DerivedSimpleMessageA { Data = "Hello" })); case 2: return(messageBus.PublishAsync(new Derived2SimpleMessageA { Data = "Hello" })); case 3: return(messageBus.PublishAsync(new Derived3SimpleMessageA { Data = "Hello" })); case 4: return(messageBus.PublishAsync(new Derived4SimpleMessageA { Data = "Hello" })); case 5: return(messageBus.PublishAsync(new Derived5SimpleMessageA { Data = "Hello" })); case 6: return(messageBus.PublishAsync(new Derived6SimpleMessageA { Data = "Hello" })); case 7: return(messageBus.PublishAsync(new Derived7SimpleMessageA { Data = "Hello" })); case 8: return(messageBus.PublishAsync(new Derived8SimpleMessageA { Data = "Hello" })); case 9: return(messageBus.PublishAsync(new Derived9SimpleMessageA { Data = "Hello" })); case 10: return(messageBus.PublishAsync(new Derived10SimpleMessageA { Data = "Hello" })); case iterations + 1: return(messageBus.PublishAsync(new { Data = "Hello" })); case iterations + 2: return(messageBus.PublishAsync(new SimpleMessageC { Data = "Hello" })); case iterations + 3: return(messageBus.PublishAsync(new SimpleMessageB { Data = "Hello" })); default: return(messageBus.PublishAsync(new SimpleMessageA { Data = "Hello" })); } }); await Task.WhenAll(subscribe, publish); await countdown.WaitAsync(TimeSpan.FromSeconds(2)); Assert.Equal(0, countdown.CurrentCount); } finally { foreach (var mb in messageBuses) { await CleanupMessageBusAsync(mb); } await CleanupMessageBusAsync(messageBus); } }
public async Task When_receiver_throws_then_work_distribution_continues() { var received = 0; var distributor = CreateDistributor(waitInterval: TimeSpan.FromMilliseconds(100)).Trace(); var countdown = new AsyncCountdownEvent(20); distributor.OnReceive(async lease => { Interlocked.Increment(ref received); if (received < 10) { throw new Exception("dangit!"); } countdown.Signal(); }); await distributor.Start(); await countdown.WaitAsync().Timeout(); await distributor.Stop(); received.Should().BeGreaterOrEqualTo(20); }