} // proc StartJob public Task ExecuteJobAsync(ICronJobExecute job, CancellationToken cancellation) { using (currentJobs.EnterWriteLock()) { if (currentJobs.FindIndex(c => job == c.Job) >= 0) { throw new InvalidOperationException("Job is already running."); } using (currentJobs.EnterReadLock()) { foreach (var j in currentJobs) { if (!job.CanRunParallelTo(j.Job)) { throw new InvalidOperationException(String.Format("Job is blocked (job: {0})", j.Job.DisplayName)); } } } Log.Info("jobstart: {0}", job.DisplayName); var currentJob = new CurrentRunningJob(this, job, cancellation); currentJobs.Add(currentJob); return(currentJob.Task); } } // func ExecuteJobAsync
} // func ExecuteJobAsync private void FinishJob(CurrentRunningJob jobRunning, Exception jobException) { lock (cronItemCache) { using (EnterReadLock()) using (currentJobs.EnterWriteLock()) { var jobBound = jobRunning.Job as ICronJobItem; // remove job from running jobs currentJobs.Remove(jobRunning); // generate log entry var name = jobBound == null ? "<unnamed>" : jobBound.DisplayName; if (jobException != null) { Log.Except(String.Format("jobfinish: {0}", name), jobException); var node = jobRunning.Job as DEConfigLogItem; if (node != null) { var aggException = jobException as AggregateException; if (aggException != null) { if (aggException.InnerException != null) { node.Log.Except("Execution failed.", aggException.InnerException); } foreach (var ex in aggException.InnerExceptions) { node.Log.Except("Execution failed.", ex); } } else { node.Log.Except("Execution failed.", jobException); } } } else { Log.Info("jobfinish: {0}", name); } // calculate next runtime if (jobBound != null && !jobBound.Bound.IsEmpty && cronItemCache != null) { var index = Array.FindIndex(cronItemCache, c => c.Job == jobBound); if (index >= 0) { var next = jobBound.Bound.GetNext(DateTime.Now); cronItemCache[index].NextRun = next; jobBound.NotifyNextRun(next); SaveNextRuntime(); } } } } } // proc FinishJob