protected async Task Run(Job job, IServiceScope scope) { var jobService = scope.ServiceProvider.GetRequiredService <IJobService>(); var procedureService = scope.ServiceProvider.GetRequiredService <IProcedureService>(); var contextFactory = scope.ServiceProvider.GetRequiredService <IContextFactory>(); var log = new JobLogger(_logger, job); var cts = new CancellationTokenSource(); var context = contextFactory.Create(job, log, cts.Token, p => job.Progress = p); jobService.RegisterCanceller(job.Id, () => cts.Cancel(true)); await Task.Factory.StartNew(() => { job.StartAt = DateTime.UtcNow; job.Status = JobStatus.Running; try { var procedure = procedureService.Resolve(job.Name); procedure.ExecuteAsync(context).Wait(context.CancellationToken); } catch (Exception ex) { var baseEx = ex.GetBaseException(); if (baseEx.GetType() == typeof(OperationCanceledException)) { log.LogInformation("<< The job has been canceled. >>"); ExceptionDispatchInfo.Capture(baseEx).Throw(); } else { log.LogError(ex, ex.Message); context.Errors.Add(new Error(ERR_EXCEPTION_THROWN)); } } }, context.CancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default) .ContinueWith(t => { foreach (var error in context.Errors) { log.LogError(error.ToString()); } job.FinishAt = DateTime.UtcNow; if (t.IsCanceled) { job.Status = JobStatus.Canceled; } else { job.Progress = 100; job.Status = context.Errors.Count == 0 ? JobStatus.Success : JobStatus.Faild; } jobService.SaveAsync(job).Wait(context.CancellationToken); }); }