private ProgressReportingTask <TResult, TProgress> GetAsynchronousResponseWithProgress <TResult, TProgress>(AsyncResults taskCompletionSource, CancellationToken cancellationToken) { ProgressReportingTask <TResult, TProgress> progressReportingTask = new ProgressReportingTask <TResult, TProgress>( progress => { object obj; while (taskCompletionSource.TryTake(out obj, (int)TimeSpan.FromMinutes(2).TotalMilliseconds, cancellationToken)) { progress.MakeProgress((TProgress)obj); if (obj is TProgress) { progress.MakeProgress((TProgress)obj); } else if (obj is TResult) { return((TResult)obj); } else { throw new ArgumentException("Cannot process result type of " + taskCompletionSource.GetConsumingEnumerable(cancellationToken).First().GetType()); } } throw new AbandonedMutexException("We did not receive of reply from the server after 2 minutes for transaction " + taskCompletionSource.Id); }, cancellationToken, TaskCreationOptions.None); progressReportingTask.Start(BackgroundTaskScheduler.OnBackground()); Task tt = progressReportingTask; tt.OnCancelled( canceled => { Trace.WriteLine("Got some more cancels"); }, UITaskScheduler.InvokeAsync()); // bug here - not being called on cancel return(progressReportingTask); }
public async Task When_Child_Task_Is_Queued(JobContinuationOptions hangfireOptions) { // Arrange var parentId = Guid.NewGuid().ToString(); var backgroundJobClient = new Mock <IBackgroundJobClient>(); var backgroundTaskExecutor = new HangfireBackgroundTaskScheduleProvider(backgroundJobClient.Object, new NullLogger <HangfireBackgroundTaskScheduleProvider>()); var backgroundTaskScheduler = new BackgroundTaskScheduler(Enumerable.Empty <IBackgroundTaskPreprocessor>(), backgroundTaskExecutor, new NullLogger <BackgroundTaskScheduler>()); backgroundJobClient.Setup(c => c.Create(It.IsAny <Job>(), It.Is <EnqueuedState>(s => s.Queue == EnqueuedState.DefaultQueue))) .Returns(parentId).Verifiable(); backgroundJobClient.Setup(c => c.Create(It.IsAny <Job>(), It.Is <AwaitingState>(s => s.ParentId == parentId && s.Options == hangfireOptions))) .Verifiable(); // Act var parentTask = backgroundTaskScheduler.Enqueue(new ParentTask()); var childTask = parentTask.ContinueWith(new ChildTask(), hangfireOptions == JobContinuationOptions.OnlyOnSucceededState ? BackgroundTaskContinuationOptions.OnlyOnSucceededState : BackgroundTaskContinuationOptions.OnAnyFinishedState); await backgroundTaskScheduler.RunNowAsync(); // Assert parentTask.Should().NotBeNull(); childTask.Should().NotBeNull(); backgroundJobClient.Verify(c => c.Create(It.IsAny <Job>(), It.Is <EnqueuedState>(s => s.Queue == EnqueuedState.DefaultQueue))); backgroundJobClient.Verify(c => c.Create(It.IsAny <Job>(), It.Is <AwaitingState>(s => s.ParentId == parentId && s.Options == hangfireOptions))); }
/// <summary> /// Start running the connector. It first does an initial push for data since the provided checkpoint, and then starts the background job cadence. /// </summary> /// <param name="cancellationToken">The task cancelation token.</param> /// <returns>The running task</returns> public async Task RunAsync(CancellationToken cancellationToken = default(CancellationToken)) { log.Info("Put on your seat-belt, starting the polling connector run."); log.Info($"Doing an initial poll with the checkpoint: {this.checkpoint.GetValue()}."); this.pusher.Push(this.db); if (this.config?.ScanInterval.TotalMilliseconds > 0) { var scheduler = new BackgroundTaskScheduler(this.config.ScanInterval); await scheduler.StartAsync(() => this.pusher.Push(this.db), cancellationToken); } }
public static async Task InitializeDatabase(IUnityContainer container) { var dataAccess = container.Resolve <IDataAccess>(Resources.DataAccessObjectName); await BackgroundTaskScheduler.QueueBackgroundWorkItem(async ct => { if (DatabaseState.New == await dataAccess.OpenOrCreateDatabaseAsync()) { await PopulateDatabase(container, dataAccess); } }); }
private Task <TResult> GetAsynchronousResponse <TResult>(AsyncResults taskCompletionSource, CancellationToken cancellationToken) { return(TaskFactoryHelper <TResult> .StartNew( () => { object obj; while (!(taskCompletionSource.TryTake(out obj, (int)TimeSpan.FromMinutes(2).TotalMilliseconds, cancellationToken))) { if (obj is TResult) { return (TResult)obj; } } throw new AbandonedMutexException("We did not receive of reply from the server after 2 minutes for transaction " + taskCompletionSource.Id); }, BackgroundTaskScheduler.OnBackground(), cancellationToken)); }
public async Task TestBackgroundTaskScheduler() { var scheduler = new BackgroundTaskScheduler(TimeSpan.FromSeconds(1)); var canceller = new CancellationTokenSource(); int occurences = 0; Task run = scheduler.StartAsync(() => occurences++, canceller.Token); await Task.Delay(TimeSpan.FromSeconds(0.5)); Assert.AreEqual(0, occurences); await Task.Delay(TimeSpan.FromSeconds(5)); Assert.AreEqual(5, occurences); canceller.Cancel(); await Task.Delay(TimeSpan.FromSeconds(2)); Assert.AreEqual(5, occurences); }
private async Task UpdateAsync(IEnumerable <ShellContext> previousShells, IEnumerable <ShellContext> runningShells, CancellationToken stoppingToken) { var referenceTime = DateTime.UtcNow; await GetShellsToUpdate(previousShells, runningShells).ForEachAsync(async shell => { var tenant = shell.Settings.Name; if (stoppingToken.IsCancellationRequested) { return; } _httpContextAccessor.HttpContext = shell.CreateHttpContext(); var shellScope = await _shellHost.GetScopeAsync(shell.Settings); if (shellScope.ShellContext.Pipeline == null) { return; } await shellScope.UsingAsync(async scope => { var tasks = scope.ServiceProvider.GetServices <IBackgroundTask>(); CleanSchedulers(tenant, tasks); if (!tasks.Any()) { return; } var settingsProvider = scope.ServiceProvider.GetService <IBackgroundTaskSettingsProvider>(); _changeTokens[tenant] = settingsProvider?.ChangeToken ?? NullChangeToken.Singleton; foreach (var task in tasks) { var taskName = task.GetTaskName(); if (!_schedulers.TryGetValue(tenant + taskName, out var scheduler)) { _schedulers[tenant + taskName] = scheduler = new BackgroundTaskScheduler(tenant, taskName, referenceTime); } if (!scheduler.Released && scheduler.Updated) { continue; } BackgroundTaskSettings settings = null; try { if (settingsProvider != null) { settings = await settingsProvider.GetSettingsAsync(task); } } catch (Exception e) { Logger.LogError(e, "Error while updating settings of background task '{TaskName}' on tenant '{TenantName}'.", taskName, tenant); } settings = settings ?? task.GetDefaultSettings(); if (scheduler.Released || !scheduler.Settings.Schedule.Equals(settings.Schedule)) { scheduler.ReferenceTime = referenceTime; } scheduler.Settings = settings; scheduler.Released = false; scheduler.Updated = true; } }); }); }
private static async Task PopulateDatabase(IUnityContainer container, IDataAccess dataAccess) { await BackgroundTaskScheduler.QueueBackgroundWorkItem(async ct => { var i = 0; var artistTable = container.Resolve <ArtistTable>(); var genreTable = container.Resolve <GenreTable>(); var albumTable = container.Resolve <AlbumTable>(); var dirName = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)); if (dirName != null) { var dataFilePath = Path.Combine(dirName, Resources.DataFile); var lines = File.ReadAllLines(dataFilePath); var lineCount = lines.Length - 1; foreach (var line in lines.Skip(1)) { // album name, artist name, genre name, year // album name might have quotes string album; string artist; string genre; int year; var parts = line.Split('"'); if (parts.Length > 1) { album = parts[1]; parts = parts[2].Split(','); artist = parts[1]; genre = parts[2]; year = int.Parse(parts[3]); } else { parts = line.Split(','); album = parts[0]; artist = parts[1]; genre = parts[2]; year = int.Parse(parts[3]); } var artistId = i; var genreId = i; var parameters = new List <SQLiteParameter>(); var artistResult = await dataAccess.ExecuteSqlWithParametersAsync(artistTable.GetInsertSql(new Artist(i, artist), ref parameters), parameters); if (artistResult <= 0) { // the artist already exists artistId = await GetExistingId(artistTable, artist, dataAccess); artistResult = artistId > 0 ? 1 : artistId; } parameters.Clear(); var genreResult = await dataAccess.ExecuteSqlWithParametersAsync(genreTable.GetInsertSql(new Genre(i, genre), ref parameters), parameters); if (genreResult <= 0) { // the genre already exists genreId = await GetExistingId(genreTable, genre, dataAccess); genreResult = genreId > 0 ? 1 : genreId; } parameters.Clear(); var albumResult = await dataAccess.ExecuteSqlWithParametersAsync(albumTable.GetInsertSql(new Album(i, artistId, genreId, album, year), ref parameters), parameters); if (albumResult <= 0) { // the album already exists throw new SQLiteException(Resources.AlbumExistsExceptionMessage); } i++; if (artistResult + genreResult + albumResult != 3) { throw new SQLiteException(Resources.ErrorAddingItemMessage); } } if (i != lineCount) { throw new SQLiteException($"Error adding data to database. There were {lineCount} items, but only {i} were added."); } } }); }
/// <summary> /// Provides a synchronous wait version of a server request and callback. /// If the caller thread is UI thread, it executes asynchronously. /// If the caller thread is not UI thread, it blocks the caller thread. /// </summary> /// <typeparam name="T">The type expected via callback.</typeparam> /// <typeparam name="TResponse"></typeparam> /// <typeparam name="TRequest"></typeparam> /// <param name="request"></param> /// <param name="svcGatewayMethod"></param> /// <param name="timeout">The time to wait before giving up on the service response.</param> /// <returns></returns> /// <remarks>Note that this does not currently support progress reporting. If the service provides progress /// reports this will need to be amended.</remarks> protected TResponse ServerRequest <TResponse, TRequest>(TRequest request, SvcGatewayDelegate <TRequest, TResponse> svcGatewayMethod, TimeSpan timeout) where TResponse : ServiceResponse where TRequest : ICommonRequest { AsyncResults asyncResults = AddToResponseQueue(request.RequestID); TimeSpan defaultTimeout = TimeSpan.FromMinutes(2); if (defaultTimeout < timeout) { timeout = defaultTimeout; } if (UIThreadSingleton.IsCreated && UIThreadSingleton.IsCallFromUIThread) { Task <TResponse> callCompleted = TaskFactoryHelper <TResponse> .StartNew( () => ExecServerRequest(request, svcGatewayMethod, timeout, asyncResults), BackgroundTaskScheduler.OnBackground()); while (!callCompleted.IsFinishedRunning()) { Application.DoEvents(); } if (callCompleted.Status != TaskStatus.RanToCompletion) { if (callCompleted.Exception != null) { AggregateException aggregateException = callCompleted.Exception.Flatten(); if (aggregateException.InnerException != null) { throw aggregateException.InnerException; } } } return(callCompleted.Result); } else { return(ExecServerRequest(request, svcGatewayMethod, timeout, asyncResults)); } }