protected override void OnStart(string[] args) { ISchedulerFactory sf; // create scheduler sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(); foreach (ServiceJob job in jobService.GetActiveJobs().ToList()) { try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); sched.ScheduleJob(jobDetail, jobTrigger); } catch (Exception ex) { // get path to the services directory String path = System.Reflection.Assembly.GetExecutingAssembly().Location; path = System.IO.Path.GetDirectoryName(path); // create a friendly error message string message = string.Format("Error loading the job: {0}. Ensure that the correct version of the job's assembly ({1}.dll) in the services directory ({2}) of your server.", job.Name, job.Assembly, path); message = message + "\n\n\n\n" + ex.Message; //throw new JobLoadFailedException( message ); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; jobService.Save(job, null); } } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); }
/// <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 Start event of the Application control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> protected void Application_Start(object sender, EventArgs e) { try { var stopwatch = System.Diagnostics.Stopwatch.StartNew(); LogMessage(APP_LOG_FILENAME, "Application Starting..."); if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { System.Diagnostics.Debug.WriteLine(string.Format("Application_Start: {0}", RockDateTime.Now.ToString("hh:mm:ss.FFF"))); } // Clear all cache RockMemoryCache.Clear(); // Get a db context using (var rockContext = new RockContext()) { if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { try { // default Initializer is CreateDatabaseIfNotExists, so set it to NULL so that nothing happens if there isn't a database yet Database.SetInitializer <Rock.Data.RockContext>(null); new AttributeService(rockContext).Get(0); System.Diagnostics.Debug.WriteLine(string.Format("ConnectToDatabase {2}/{1} - {0} ms", stopwatch.Elapsed.TotalMilliseconds, rockContext.Database.Connection.Database, rockContext.Database.Connection.DataSource)); } catch { // Intentionally Blank } } //// Run any needed Rock and/or plugin migrations //// NOTE: MigrateDatabase must be the first thing that touches the database to help prevent EF from creating empty tables for a new database MigrateDatabase(rockContext); // Preload the commonly used objects stopwatch.Restart(); LoadCacheObjects(rockContext); if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { System.Diagnostics.Debug.WriteLine(string.Format("LoadCacheObjects - {0} ms", stopwatch.Elapsed.TotalMilliseconds)); } // Run any plugin migrations MigratePlugins(rockContext); RegisterRoutes(rockContext, RouteTable.Routes); // Configure Rock Rest API stopwatch.Restart(); GlobalConfiguration.Configure(Rock.Rest.WebApiConfig.Register); if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { System.Diagnostics.Debug.WriteLine(string.Format("Configure WebApiConfig - {0} ms", stopwatch.Elapsed.TotalMilliseconds)); stopwatch.Restart(); } // setup and launch the jobs infrastructure if running under IIS bool runJobsInContext = Convert.ToBoolean(ConfigurationManager.AppSettings["RunJobsInIISContext"]); if (runJobsInContext) { ISchedulerFactory sf; // create scheduler sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(rockContext); foreach (ServiceJob job in jobService.GetActiveJobs().ToList()) { const string errorLoadingStatus = "Error Loading Job"; try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); sched.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 ex) { // log the error LogError(ex, null); // create a friendly error message string message = string.Format("Error loading the job: {0}.\n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = errorLoadingStatus; rockContext.SaveChanges(); } } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); } // Force the static Liquid class to get instantiated so that the standard filters are loaded prior // to the custom RockFilter. This is to allow the custom 'Date' filter to replace the standard // Date filter. Liquid.UseRubyDateFormat = false; //// NOTE: This means that template filters will also use CSharpNamingConvention //// For example the dotliquid documentation says to do this for formatting dates: //// {{ some_date_value | date:"MMM dd, yyyy" }} //// However, if CSharpNamingConvention is enabled, it needs to be: //// {{ some_date_value | Date:"MMM dd, yyyy" }} Template.NamingConvention = new DotLiquid.NamingConventions.CSharpNamingConvention(); Template.FileSystem = new RockWeb.LavaFileSystem(); Template.RegisterSafeType(typeof(Enum), o => o.ToString()); Template.RegisterFilter(typeof(Rock.Lava.RockFilters)); // add call back to keep IIS process awake at night and to provide a timer for the queued transactions AddCallBack(); Rock.Security.Authorization.Load(); } EntityTypeService.RegisterEntityTypes(Server.MapPath("~")); FieldTypeService.RegisterFieldTypes(Server.MapPath("~")); BundleConfig.RegisterBundles(BundleTable.Bundles); // mark any user login stored as 'IsOnline' in the database as offline MarkOnlineUsersOffline(); SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~")); LogMessage(APP_LOG_FILENAME, "Application Started Successfully"); if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { System.Diagnostics.Debug.WriteLine(string.Format("Application_Started_Successfully: {0}", RockDateTime.Now.ToString("hh:mm:ss.FFF"))); } } catch (Exception ex) { SetError66(); throw (new Exception("Error occurred during application startup", ex)); } }
/// <summary> /// Handles the Start event of the Application control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> protected void Application_Start(object sender, EventArgs e) { if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { HttpInternals.RockWebFileChangeMonitor(); } // Check if database should be auto-migrated for the core and plugins bool autoMigrate = true; if (!Boolean.TryParse(ConfigurationManager.AppSettings["AutoMigrateDatabase"], out autoMigrate)) { autoMigrate = true; } if (autoMigrate) { try { Database.SetInitializer(new MigrateDatabaseToLatestVersion <Rock.Data.RockContext, Rock.Migrations.Configuration>()); // explictly check if the database exists, and force create it if doesn't exist Rock.Data.RockContext rockContext = new Rock.Data.RockContext(); if (!rockContext.Database.Exists()) { rockContext.Database.Initialize(true); } else { var migrator = new System.Data.Entity.Migrations.DbMigrator(new Rock.Migrations.Configuration()); migrator.Update(); } // Migrate any plugins that have pending migrations List <Type> configurationTypeList = Rock.Reflection.FindTypes(typeof(System.Data.Entity.Migrations.DbMigrationsConfiguration)).Select(a => a.Value).ToList(); foreach (var configType in configurationTypeList) { if (configType != typeof(Rock.Migrations.Configuration)) { var config = Activator.CreateInstance(configType) as System.Data.Entity.Migrations.DbMigrationsConfiguration; System.Data.Entity.Migrations.DbMigrator pluginMigrator = Activator.CreateInstance(typeof(System.Data.Entity.Migrations.DbMigrator), config) as System.Data.Entity.Migrations.DbMigrator; pluginMigrator.Update(); } } } catch (Exception ex) { // if migrations fail, log error and attempt to continue LogError(ex, -1, string.Empty, HttpContext.Current); } } else { // default Initializer is CreateDatabaseIfNotExists, but we don't want that to happen if automigrate is false, so set it to NULL so that nothing happens Database.SetInitializer <Rock.Data.RockContext>(null); } // Preload the commonly used objects LoadCacheObjects(); // setup and launch the jobs infrastructure if running under IIS bool runJobsInContext = Convert.ToBoolean(ConfigurationManager.AppSettings["RunJobsInIISContext"]); if (runJobsInContext) { ISchedulerFactory sf; // create scheduler sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(); foreach (ServiceJob job in jobService.GetActiveJobs().ToList()) { try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); sched.ScheduleJob(jobDetail, jobTrigger); } catch (Exception ex) { // create a friendly error message string message = string.Format("Error loading the job: {0}. Ensure that the correct version of the job's assembly ({1}.dll) in the websites App_Code directory. \n\n\n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; jobService.Save(job, null); } } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); } // add call back to keep IIS process awake at night and to provide a timer for the queued transactions AddCallBack(); RegisterFilters(GlobalConfiguration.Configuration.Filters); RegisterRoutes(RouteTable.Routes); Rock.Security.Authorization.Load(); AddEventHandlers(); new EntityTypeService().RegisterEntityTypes(Server.MapPath("~")); new FieldTypeService().RegisterFieldTypes(Server.MapPath("~")); BundleConfig.RegisterBundles(BundleTable.Bundles); }
/// <summary> /// Updates the scheduled jobs. /// </summary> /// <param name="context">The context.</param> private void UpdateScheduledJobs(IJobExecutionContext context) { var scheduler = context.Scheduler; int jobsDeleted = 0; int jobsScheduleUpdated = 0; var rockContext = new Rock.Data.RockContext(); ServiceJobService jobService = new ServiceJobService(rockContext); List <ServiceJob> activeJobList = jobService.GetActiveJobs().ToList(); List <Quartz.JobKey> scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList(); // delete any jobs that are no longer exist (are are not set to active) in the database var quartsJobsToDelete = scheduledQuartzJobs.Where(a => !activeJobList.Any(j => j.Guid.Equals(a.Name.AsGuid()))); foreach (JobKey jobKey in quartsJobsToDelete) { scheduler.DeleteJob(jobKey); jobsDeleted++; } // add any jobs that are not yet scheduled var newActiveJobs = activeJobList.Where(a => !scheduledQuartzJobs.Any(q => q.Name.AsGuid().Equals(a.Guid))); foreach (Rock.Model.ServiceJob job in newActiveJobs) { const string errorSchedulingStatus = "Error scheduling Job"; try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); scheduler.ScheduleJob(jobDetail, jobTrigger); jobsScheduleUpdated++; if (job.LastStatus == errorSchedulingStatus) { job.LastStatusMessage = string.Empty; job.LastStatus = string.Empty; rockContext.SaveChanges(); } } catch (Exception ex) { ExceptionLogService.LogException(ex, null); // create a friendly error message string message = string.Format("Error scheduling the job: {0}.\n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = errorSchedulingStatus; } } rockContext.SaveChanges(); // reload the jobs in case any where added/removed scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList(); // update schedule if the schedule has changed foreach (var jobKey in scheduledQuartzJobs) { var jobCronTrigger = scheduler.GetTriggersOfJob(jobKey).OfType <ICronTrigger>().FirstOrDefault(); if (jobCronTrigger != null) { var activeJob = activeJobList.FirstOrDefault(a => a.Guid.Equals(jobKey.Name.AsGuid())); if (activeJob != null) { bool rescheduleJob = false; // fix up the schedule if it has changed if (activeJob.CronExpression != jobCronTrigger.CronExpressionString) { rescheduleJob = true; } // update the job detail if it has changed var scheduledJobDetail = scheduler.GetJobDetail(jobKey); var jobDetail = jobService.BuildQuartzJob(activeJob); if (scheduledJobDetail != null && jobDetail != null) { if (scheduledJobDetail.JobType != jobDetail.JobType) { rescheduleJob = true; } if (scheduledJobDetail.JobDataMap.ToJson() != jobDetail.JobDataMap.ToJson()) { rescheduleJob = true; } } if (rescheduleJob) { const string errorReschedulingStatus = "Error re-scheduling Job"; try { ITrigger newJobTrigger = jobService.BuildQuartzTrigger(activeJob); bool deletedSuccessfully = scheduler.DeleteJob(jobKey); scheduler.ScheduleJob(jobDetail, newJobTrigger); jobsScheduleUpdated++; if (activeJob.LastStatus == errorReschedulingStatus) { activeJob.LastStatusMessage = string.Empty; activeJob.LastStatus = string.Empty; rockContext.SaveChanges(); } } catch (Exception ex) { ExceptionLogService.LogException(ex, null); // create a friendly error message string message = string.Format("Error re-scheduling the job: {0}.\n\n{2}", activeJob.Name, activeJob.Assembly, ex.Message); activeJob.LastStatusMessage = message; activeJob.LastStatus = errorReschedulingStatus; } } } } } context.Result = string.Empty; if (jobsDeleted > 0) { context.Result += string.Format("Deleted {0} job schedule(s)", jobsDeleted); } if (jobsScheduleUpdated > 0) { context.Result += (string.IsNullOrEmpty(context.Result as string) ? "" : " and ") + string.Format("Updated {0} schedule(s)", jobsScheduleUpdated); } }
/// <summary> /// Starts the job scheduler. /// </summary> public void StartJobScheduler() { if (!System.IO.File.Exists("web.connectionstrings.config")) { // Write an eventlog about web.connectionstring.config not found this.EventLog.WriteEntry("Unable to find web.connectionstrings.config", EventLogEntryType.Error); } ISchedulerFactory sf; // create scheduler sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); var rockContext = new RockContext(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(rockContext); List <ServiceJob> activeJobs = null; try { // make sure that we can connect to the database and get the jobs list. Write a good EventLog message and exit the app if we can't this.EventLog.WriteEntry(string.Format("Connecting to database {0}:{1}", rockContext.Database.Connection.DataSource, rockContext.Database.Connection.Database), EventLogEntryType.Information); rockContext.Database.Connection.Open(); activeJobs = jobService.GetActiveJobs().ToList(); } catch (Exception ex) { this.EventLog.WriteEntry("Unable load active jobs list. " + ex.Message, EventLogEntryType.Error); throw ex; } foreach (ServiceJob job in activeJobs) { try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); sched.ScheduleJob(jobDetail, jobTrigger); } catch (Exception ex) { // get path to the services directory string path = System.Reflection.Assembly.GetExecutingAssembly().Location; path = System.IO.Path.GetDirectoryName(path); // create a friendly error message string message = string.Format("Error loading the job: {0}. Ensure that the correct version of the job's assembly ({1}.dll) in the services directory ({2}) of your server.", job.Name, job.Assembly, path); message = message + "\n\n\n\n" + ex.Message; //throw new JobLoadFailedException( message ); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; rockContext.SaveChanges(); } } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); }
/// <summary> /// Handles the Start event of the Application control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> protected void Application_Start(object sender, EventArgs e) { try { if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { System.Diagnostics.Debug.WriteLine(string.Format("Application_Start: {0}", RockDateTime.Now.ToString("hh:mm:ss.FFF"))); } // Run any needed Rock and/or plugin migrations MigrateDatabase(); // Get a db context var rockContext = new RockContext(); RegisterRoutes(rockContext, RouteTable.Routes); if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { new AttributeService(rockContext).Get(0); System.Diagnostics.Debug.WriteLine(string.Format("ConnectToDatabase - Connected: {0}", RockDateTime.Now.ToString("hh:mm:ss.FFF"))); } // Preload the commonly used objects LoadCacheObjects(rockContext); if (System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment) { System.Diagnostics.Debug.WriteLine(string.Format("LoadCacheObjects - Done: {0}", RockDateTime.Now.ToString("hh:mm:ss.FFF"))); } // setup and launch the jobs infrastructure if running under IIS bool runJobsInContext = Convert.ToBoolean(ConfigurationManager.AppSettings["RunJobsInIISContext"]); if (runJobsInContext) { ISchedulerFactory sf; // create scheduler sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(rockContext); foreach (ServiceJob job in jobService.GetActiveJobs().ToList()) { try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); sched.ScheduleJob(jobDetail, jobTrigger); } catch (Exception ex) { // create a friendly error message string message = string.Format("Error loading the job: {0}. Ensure that the correct version of the job's assembly ({1}.dll) in the websites App_Code directory. \n\n\n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; rockContext.SaveChanges(); } } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); } // add call back to keep IIS process awake at night and to provide a timer for the queued transactions AddCallBack(); RegisterFilters(GlobalConfiguration.Configuration.Filters); Rock.Security.Authorization.Load(rockContext); EntityTypeService.RegisterEntityTypes(Server.MapPath("~")); FieldTypeService.RegisterFieldTypes(Server.MapPath("~")); BundleConfig.RegisterBundles(BundleTable.Bundles); // mark any user login stored as 'IsOnline' in the database as offline MarkOnlineUsersOffline(); SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~")); } catch (Exception ex) { Error66(ex); } }
/// <summary> /// Updates the scheduled jobs. /// </summary> /// <param name="context">The context.</param> private void UpdateScheduledJobs(IJobExecutionContext context) { var scheduler = context.Scheduler; var rockContext = new Rock.Data.RockContext(); ServiceJobService jobService = new ServiceJobService(rockContext); List <ServiceJob> activeJobList = jobService.GetActiveJobs().ToList(); List <Quartz.JobKey> scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList(); // delete any jobs that are no longer exist (are are not set to active) in the database var quartsJobsToDelete = scheduledQuartzJobs.Where(a => !activeJobList.Any(j => j.Guid.Equals(a.Name.AsGuid()))); foreach (JobKey jobKey in quartsJobsToDelete) { scheduler.DeleteJob(jobKey); } // add any jobs that are not yet scheduled var newActiveJobs = activeJobList.Where(a => !scheduledQuartzJobs.Any(q => q.Name.AsGuid().Equals(a.Guid))); foreach (Rock.Model.ServiceJob job in newActiveJobs) { try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); scheduler.ScheduleJob(jobDetail, jobTrigger); } catch (Exception ex) { // create a friendly error message string message = string.Format("Error loading the job: {0}. Ensure that the correct version of the job's assembly ({1}.dll) in the websites App_Code directory. \n\n\n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; } } rockContext.SaveChanges(); // reload the jobs in case any where added/removed scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList(); // update schedule if the schedule has changed foreach (var jobKey in scheduledQuartzJobs) { var jobCronTrigger = scheduler.GetTriggersOfJob(jobKey).OfType <ICronTrigger>().FirstOrDefault(); if (jobCronTrigger != null) { var activeJob = activeJobList.FirstOrDefault(a => a.Guid.Equals(jobKey.Name.AsGuid())); if (activeJob != null) { bool rescheduleJob = false; // fix up the schedule if it has changed if (activeJob.CronExpression != jobCronTrigger.CronExpressionString) { rescheduleJob = true; } // update the job detail if it has changed var scheduledJobDetail = scheduler.GetJobDetail(jobKey); var jobDetail = jobService.BuildQuartzJob(activeJob); if (scheduledJobDetail != null && jobDetail != null) { if (scheduledJobDetail.JobType != jobDetail.JobType) { rescheduleJob = true; } if (scheduledJobDetail.JobDataMap.ToJson() != jobDetail.JobDataMap.ToJson()) { rescheduleJob = true; } } if (rescheduleJob) { ITrigger newJobTrigger = jobService.BuildQuartzTrigger(activeJob); scheduler.DeleteJob(jobKey); scheduler.ScheduleJob(jobDetail, newJobTrigger); } } } } }
/// <summary> /// Handles the Start event of the Application control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> protected void Application_Start(object sender, EventArgs e) { // Check if database should be auto-migrated bool autoMigrate = true; if (!Boolean.TryParse(ConfigurationManager.AppSettings["AutoMigrateDatabase"], out autoMigrate)) { autoMigrate = true; } if (autoMigrate) { Database.SetInitializer(new MigrateDatabaseToLatestVersion <Rock.Data.RockContext, Rock.Migrations.Configuration>()); } // Preload the commonly used objects LoadCacheObjects(); // setup and launch the jobs infrastructure if running under IIS bool runJobsInContext = Convert.ToBoolean(ConfigurationManager.AppSettings["RunJobsInIISContext"]); if (runJobsInContext) { ISchedulerFactory sf; // create scheduler sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(); foreach (ServiceJob job in jobService.GetActiveJobs().ToList()) { try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); sched.ScheduleJob(jobDetail, jobTrigger); } catch (Exception ex) { // create a friendly error message string message = string.Format("Error loading the job: {0}. Ensure that the correct version of the job's assembly ({1}.dll) in the websites App_Code directory. \n\n\n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = "Error Loading Job"; jobService.Save(job, null); } } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); } // add call back to keep IIS process awake at night and to provide a timer for the queued transactions AddCallBack(); RegisterFilters(GlobalConfiguration.Configuration.Filters); RegisterRoutes(RouteTable.Routes); Rock.Security.Authorization.Load(); AddEventHandlers(); }
/// <summary> /// Starts the job scheduler. /// </summary> public void StartJobScheduler() { if (!System.IO.File.Exists("web.connectionstrings.config")) { // Write an eventlog about web.connectionstring.config not found this.EventLog.WriteEntry("Unable to find web.connectionstrings.config", EventLogEntryType.Error); } ISchedulerFactory sf; // create scheduler sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); var rockContext = new RockContext(); // get list of active jobs ServiceJobService jobService = new ServiceJobService(rockContext); List <ServiceJob> activeJobs = null; try { // make sure that we can connect to the database and get the jobs list. Write a good EventLog message and exit the app if we can't this.EventLog.WriteEntry(string.Format("Connecting to database {0}:{1}", rockContext.Database.Connection.DataSource, rockContext.Database.Connection.Database), EventLogEntryType.Information); rockContext.Database.Connection.Open(); activeJobs = jobService.GetActiveJobs().ToList(); } catch (Exception ex) { this.EventLog.WriteEntry("Unable load active jobs list. " + ex.Message, EventLogEntryType.Error); throw ex; } foreach (ServiceJob job in activeJobs) { const string errorLoadingStatus = "Error Loading Job"; try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); sched.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 ex) { ExceptionLogService.LogException(ex, null); // get path to the services directory string path = System.Reflection.Assembly.GetExecutingAssembly().Location; path = System.IO.Path.GetDirectoryName(path); // create the error message string message = string.Format("Error loading the job: {0}.\n\n{1}\n\n Job Assembly: {2}, Path: {3}", job.Name, ex.Message, job.Assembly, path); job.LastStatusMessage = message; job.LastStatus = errorLoadingStatus; rockContext.SaveChanges(); } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); } // set up the listener to report back from jobs as they complete sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); }