/// <summary> /// Runner for <see cref="JobHandler"/>s /// </summary> /// <param name="job">The <see cref="Job"/> being run</param> /// <param name="operation">The <see cref="JobEntrypoint"/> for the <paramref name="job"/></param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param> /// <returns>A <see cref="Task"/> representing the running operation</returns> async Task RunJob(Job job, JobEntrypoint operation, CancellationToken cancellationToken) { using (LogContext.PushProperty("Job", job.Id)) try { void LogException(Exception ex) => logger.LogDebug(ex, "Job {0} exited with error!", job.Id); try { var oldJob = job; job = new Job { Id = oldJob.Id }; void UpdateProgress(int progress) { lock (synchronizationLock) if (jobs.TryGetValue(oldJob.Id.Value, out var handler)) { handler.Progress = progress; } } await activationTcs.Task.WithToken(cancellationToken).ConfigureAwait(false); logger.LogTrace("Starting job..."); await operation( instanceCoreProvider.Value.GetInstance(oldJob.Instance), databaseContextFactory, job, UpdateProgress, cancellationToken) .ConfigureAwait(false); logger.LogDebug("Job {0} completed!", job.Id); } catch (OperationCanceledException ex) { logger.LogDebug(ex, "Job {0} cancelled!", job.Id); job.Cancelled = true; } catch (JobException e) { job.ErrorCode = e.ErrorCode; job.ExceptionDetails = String.IsNullOrWhiteSpace(e.Message) ? e.InnerException?.Message : e.Message; LogException(e); } catch (Exception e) { job.ExceptionDetails = e.ToString(); LogException(e); } await databaseContextFactory.UseContext(async databaseContext => { var attachedJob = new Job { Id = job.Id }; databaseContext.Jobs.Attach(attachedJob); attachedJob.StoppedAt = DateTimeOffset.UtcNow; attachedJob.ExceptionDetails = job.ExceptionDetails; attachedJob.ErrorCode = job.ErrorCode; attachedJob.Cancelled = job.Cancelled; // DCT: Cancellation token is for job, operation should always run await databaseContext.Save(default).ConfigureAwait(false);
/// <inheritdoc /> public Task RegisterOperation(Job job, JobEntrypoint operation, CancellationToken cancellationToken) => databaseContextFactory.UseContext(