/// <summary> /// Adds the service job history. /// </summary> /// <param name="job">The job.</param> /// <param name="rockContext">The rock context.</param> private void AddServiceJobHistory(ServiceJob job, RockContext rockContext) { var jobHistoryService = new ServiceJobHistoryService(rockContext); var jobHistory = new ServiceJobHistory() { ServiceJobId = job.Id, StartDateTime = job.LastRunDateTime?.AddSeconds(0.0d - ( double )job.LastRunDurationSeconds), StopDateTime = job.LastRunDateTime, Status = job.LastStatus, StatusMessage = job.LastStatusMessage, ServiceWorker = Environment.MachineName.ToLower() }; jobHistoryService.Add(jobHistory); rockContext.SaveChanges(); }
/// <summary> /// Starts the job scheduler. /// </summary> private static void StartJobScheduler() { using (var rockContext = new RockContext()) { // create scheduler ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); QuartzScheduler = schedulerFactory.GetScheduler(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(rockContext); var activeJobList = jobService.GetActiveJobs().OrderBy(a => a.Name).ToList(); foreach (ServiceJob job in activeJobList) { const string ErrorLoadingStatus = "Error Loading Job"; try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); // Schedule the job (unless the cron expression is set to never run for an on-demand job like rebuild streaks) if (job.CronExpression != ServiceJob.NeverScheduledCronExpression) { QuartzScheduler.ScheduleJob(jobDetail, jobTrigger); } //// if the last status was an error, but we now loaded successful, clear the error // also, if the last status was 'Running', clear that status because it would have stopped if the app restarted if (job.LastStatus == ErrorLoadingStatus || job.LastStatus == "Running") { job.LastStatusMessage = string.Empty; job.LastStatus = string.Empty; rockContext.SaveChanges(); } } catch (Exception exception) { // create a friendly error message string message = $"Error loading the job: {job.Name}.\n\n{exception.Message}"; // log the error var startupException = new RockStartupException(message, exception); LogError(startupException, null); job.LastStatusMessage = message; job.LastStatus = ErrorLoadingStatus; job.LastStatus = ErrorLoadingStatus; rockContext.SaveChanges(); var jobHistoryService = new ServiceJobHistoryService(rockContext); var jobHistory = new ServiceJobHistory() { ServiceJobId = job.Id, StartDateTime = RockDateTime.Now, StopDateTime = RockDateTime.Now, Status = job.LastStatus, StatusMessage = job.LastStatusMessage }; jobHistoryService.Add(jobHistory); rockContext.SaveChanges(); } } // set up the listener to report back from jobs as they complete QuartzScheduler.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // set up a trigger listener that can prevent a job from running if another scheduler is // already running it (i.e., someone running it manually). QuartzScheduler.ListenerManager.AddTriggerListener(new RockTriggerListener(), EverythingMatcher <JobKey> .AllTriggers()); // start the scheduler QuartzScheduler.Start(); } }
/// <summary> /// Handles the RowDataBound event of the gScheduledJobHistory control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewRowEventArgs"/> instance containing the event data.</param> protected void gScheduledJobHistory_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e) { var site = RockPage.Site; if (e.Row.RowType == DataControlRowType.DataRow) { ServiceJobHistory serviceJobHistory = e.Row.DataItem as ServiceJobHistory; if (serviceJobHistory == null) { return; } // format duration if (serviceJobHistory.DurationSeconds.HasValue) { int durationSeconds = serviceJobHistory.DurationSeconds.Value; TimeSpan duration = TimeSpan.FromSeconds(durationSeconds); var lDurationSeconds = e.Row.FindControl("lDurationSeconds") as Literal; if (lDurationSeconds != null) { if (duration.Days > 0) { lDurationSeconds.Text = duration.TotalHours.ToString("F2") + " hours"; } else if (duration.Hours > 0) { lDurationSeconds.Text = String.Format("{0:%h}h {0:%m}m {0:%s}s", duration); } else if (duration.Minutes > 0) { lDurationSeconds.Text = String.Format("{0:%m}m {0:%s}s", duration); } else { lDurationSeconds.Text = String.Format("{0:%s}s", duration); } } } // format last status var lStatus = e.Row.FindControl("lStatus") as Literal; if (lStatus != null) { string status = serviceJobHistory.Status ?? string.Empty; switch (status) { case "Success": lStatus.Text = "<span class='label label-success'>Success</span>"; break; case "Running": lStatus.Text = "<span class='label label-info'>Running</span>"; break; case "Exception": lStatus.Text = "<span class='label label-danger'>Failed</span>"; break; case "Warning": lStatus.Text = "<span class='label label-warning'>Warning</span>"; break; case "": lStatus.Text = ""; break; default: lStatus.Text = String.Format("<span class='label label-warning'>{0}</span>", status); break; } var lStatusMessageAsHtml = e.Row.FindControl("lStatusMessageAsHtml") as Literal; if (lStatusMessageAsHtml != null) { lStatusMessageAsHtml.Text = serviceJobHistory.StatusMessageAsHtml; } } } }
/// <summary> /// Executes this instance. /// </summary> public void Execute() { using (var rockContext = new RockContext()) { var jobService = new ServiceJobService(rockContext); ServiceJob job = jobService.Get(JobId); if (job != null) { try { // create a scheduler specific for the job var scheduleConfig = new System.Collections.Specialized.NameValueCollection(); var runNowSchedulerName = ("RunNow:" + job.Guid.ToString("N")).Truncate(40); scheduleConfig.Add(StdSchedulerFactory.PropertySchedulerInstanceName, runNowSchedulerName); var schedulerFactory = new StdSchedulerFactory(scheduleConfig); var sched = new StdSchedulerFactory(scheduleConfig).GetScheduler(); if (sched.IsStarted) { // the job is currently running as a RunNow job return; } // create the quartz job and trigger IJobDetail jobDetail = jobService.BuildQuartzJob(job); var jobTrigger = TriggerBuilder.Create() .WithIdentity(job.Guid.ToString(), job.Name) .StartNow() .Build(); // schedule the job sched.ScheduleJob(jobDetail, jobTrigger); // set up the listener to report back from the job when it completes sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); // Wait 10secs to give job chance to start System.Threading.Tasks.Task.Delay(new TimeSpan(0, 0, 10)).Wait(); // stop the scheduler when done with job sched.Shutdown(true); } catch (Exception ex) { // create a friendly error message ExceptionLogService.LogException(ex, null); string message = string.Format("Error doing a 'Run Now' on job: {0}. \n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; rockContext.SaveChanges(); var jobHistoryService = new ServiceJobHistoryService(rockContext); var jobHistory = new ServiceJobHistory() { ServiceJobId = job.Id, StartDateTime = RockDateTime.Now, StopDateTime = RockDateTime.Now, Status = job.LastStatus, StatusMessage = job.LastStatusMessage }; jobHistoryService.Add(jobHistory); rockContext.SaveChanges(); } } } }
/// <summary> /// Executes this instance. /// </summary> public void Execute() { using (var rockContext = new RockContext()) { var jobService = new ServiceJobService(rockContext); ServiceJob job = jobService.Get(JobId); if (job != null) { try { // create a scheduler specific for the job var scheduleConfig = new System.Collections.Specialized.NameValueCollection(); var runNowSchedulerName = ("RunNow:" + job.Guid.ToString("N")).Truncate(40); scheduleConfig.Add(StdSchedulerFactory.PropertySchedulerInstanceName, runNowSchedulerName); var schedulerFactory = new StdSchedulerFactory(scheduleConfig); var sched = new StdSchedulerFactory(scheduleConfig).GetScheduler(); if (sched.IsStarted) { // the job is currently running as a RunNow job return; } // Check if another scheduler is running this job try { var otherSchedulers = new Quartz.Impl.StdSchedulerFactory().AllSchedulers .Where(s => s.SchedulerName != runNowSchedulerName); foreach (var scheduler in otherSchedulers) { if (scheduler.GetCurrentlyExecutingJobs().Where(j => j.JobDetail.Description == JobId.ToString() && j.JobDetail.ConcurrentExectionDisallowed).Any()) { // A job with that Id is already running and ConcurrentExectionDisallowed is true System.Diagnostics.Debug.WriteLine(RockDateTime.Now.ToString() + $" Scheduler '{scheduler.SchedulerName}' is already executing job Id '{JobId}' (name: {job.Name})"); return; } } } catch { } // create the quartz job and trigger IJobDetail jobDetail = jobService.BuildQuartzJob(job); if (_jobDataMapDictionary != null) { // Force the <string, string> dictionary so that within Jobs, it is always okay to use // JobDataMap.GetString(). This mimics Rock attributes always being stored as strings. // If we allow non-strings, like integers, then JobDataMap.GetString() throws an exception. jobDetail.JobDataMap.PutAll(_jobDataMapDictionary.ToDictionary(kvp => kvp.Key, kvp => ( object )kvp.Value)); } var jobTrigger = TriggerBuilder.Create() .WithIdentity(job.Guid.ToString(), job.Name) .StartNow() .Build(); // schedule the job sched.ScheduleJob(jobDetail, jobTrigger); // set up the listener to report back from the job when it completes sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); // Wait 10secs to give job chance to start System.Threading.Tasks.Task.Delay(new TimeSpan(0, 0, 10)).Wait(); // stop the scheduler when done with job sched.Shutdown(true); } catch (Exception ex) { // create a friendly error message ExceptionLogService.LogException(ex, null); string message = string.Format("Error doing a 'Run Now' on job: {0}. \n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; rockContext.SaveChanges(); var jobHistoryService = new ServiceJobHistoryService(rockContext); var jobHistory = new ServiceJobHistory() { ServiceJobId = job.Id, StartDateTime = RockDateTime.Now, StopDateTime = RockDateTime.Now, Status = job.LastStatus, StatusMessage = job.LastStatusMessage }; jobHistoryService.Add(jobHistory); rockContext.SaveChanges(); } } } }