public static (Guid JobId, DateTime StartTime, Task Task) StartNewJob(BaseJob job) { var dbJob = new Job { Id = Guid.NewGuid(), StartTime = DateTime.UtcNow, RelatedEntity = job.RelatedEntityId, Description = job.Description, Status = JobStatus.Running }; using (var ctx = new DataContext()) { ctx.Jobs.Add(dbJob); ctx.SaveChanges(); ctx.Entry(dbJob).State = EntityState.Detached; } if (!_activeJobs.TryGetValue(dbJob.RelatedEntity, out var jobList)) { _activeJobs.Add(dbJob.RelatedEntity, new List <Job>()); } _activeJobs[dbJob.RelatedEntity].Add(dbJob); Task task = null; bool taskSetup = false; _ = Task.Run(async() => { using (var ctx = new DataContext()) { ctx.Jobs.Attach(dbJob); job.ReportError = async x => await SaveError(x, dbJob, ctx); taskSetup = true; task = job.JobTask(); while (!task.IsCompleted) { dbJob.Heartbeat = DateTime.UtcNow; await ctx.SaveChangesAsync(); await Task.Delay(1000); } if (task.IsFaulted) { await SaveError(task.Exception.GetBaseException().Message, dbJob, ctx); dbJob.Status = JobStatus.Error; } else if (dbJob.Errors != null) { dbJob.Status = JobStatus.FinishedWithErrors; } else { dbJob.Status = JobStatus.Finished; } await ctx.SaveChangesAsync(); _activeJobs[dbJob.RelatedEntity].Remove(dbJob); if (!_activeJobs[dbJob.RelatedEntity].Any()) { _activeJobs.Remove(dbJob.RelatedEntity); } } }); while (!taskSetup) { Task.Delay(10).GetAwaiter().GetResult(); } return(dbJob.Id, dbJob.StartTime, task); }