/// <summary> /// Resume an active job or trigger new job from job store. /// and execute the job. /// </summary> /// <param name="cancellationToken">cancellation token.</param> /// <returns>Completed task.</returns> public async Task RunAsync(CancellationToken cancellationToken = default) { _logger.LogInformation("Job starts running."); // Acquire an active job from the job store. var job = await _jobStore.AcquireActiveJobAsync(cancellationToken) ?? await CreateNewJobAsync(cancellationToken); if (job == null) { _logger.LogWarning("Job has been scheduled to end."); // release job lock Dispose(); } else { _logger.LogInformation($"The running job id is {job.Id}"); // Update the running job to job store. // For new/resume job, add the created job to job store; For active job, update the last heart beat. await _jobStore.UpdateJobAsync(job, cancellationToken); try { job.Status = JobStatus.Running; await _jobExecutor.ExecuteAsync(job, cancellationToken); job.Status = JobStatus.Succeeded; await _jobStore.CompleteJobAsync(job, cancellationToken); } catch (Exception exception) { job.Status = JobStatus.Failed; job.FailedReason = exception.ToString(); await _jobStore.CompleteJobAsync(job, cancellationToken); _logger.LogError(exception, "Process job '{jobId}' failed.", job.Id); throw; } } }