Пример #1
0
        /// <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);
Пример #2
0
 /// <inheritdoc />
 public Task RegisterOperation(Job job, JobEntrypoint operation, CancellationToken cancellationToken)
 => databaseContextFactory.UseContext(