Service/Data access class for Rock.Model.ServiceJob entity objects.
Beispiel #1
0
        public override bool Execute( RockContext rockContext, WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            errorMessages = new List<string>();

            var JobGuid = GetAttributeValue( action, "Job" ).AsGuid();

            if ( !JobGuid.IsEmpty() )
            {
                ServiceJob Job = new ServiceJobService( rockContext ).Get( JobGuid );
                if ( Job != null )
                {
                    var transaction = new Rock.Transactions.RunJobNowTransaction( Job.Id );

                    // Process the transaction on another thread
                    System.Threading.Tasks.Task.Run( () => transaction.Execute() );

                    action.AddLogEntry( string.Format( "The '{0}' job has been started.", Job.Name ) );

                    return true;
                }

            }

            errorMessages.Add("The specified Job could not be found");

            return false;
        }
Beispiel #2
0
        /// <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 )
                    {
                        if ( activeJob.CronExpression != jobCronTrigger.CronExpressionString )
                        {
                            ITrigger newJobTrigger = jobService.BuildQuartzTrigger( activeJob );
                            scheduler.RescheduleJob( jobCronTrigger.Key, newJobTrigger );
                        }
                    }
                }
            }
        }
Beispiel #3
0
        /// <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
                        Thread.Sleep( new TimeSpan( 0, 0, 10 ) );

                        // 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();
                    }
                }
            }
        }
        /// <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
                        var scheduleConfig = new System.Collections.Specialized.NameValueCollection();
                        scheduleConfig.Add( "org.quartz.scheduler.instanceName", "RunNow" );
                        var sched = new StdSchedulerFactory( scheduleConfig ).GetScheduler();

                        // 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
                        Thread.Sleep( new TimeSpan( 0, 0, 10 ) );

                        // stop the scheduler when done with job
                        sched.Shutdown( true );
                    }

                    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();
                    }
                }
            }
        }
Beispiel #5
0
        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>
        /// Handles the Delete event of the grdScheduledJobs control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RowEventArgs" /> instance containing the event data.</param>
        protected void gScheduledJobs_Delete( object sender, RowEventArgs e )
        {
            var rockContext = new RockContext();
            var jobService = new ServiceJobService( rockContext );
            ServiceJob job = jobService.Get( e.RowKeyId );

            string errorMessage;
            if ( !jobService.CanDelete( job, out errorMessage ) )
            {
                mdGridWarning.Show( errorMessage, ModalAlertType.Information );
                return;
            }

            jobService.Delete( job );
            rockContext.SaveChanges();

            BindGrid();
        }
        /// <summary>
        /// Deletes job history items more than maximum.
        /// </summary>
        /// <param name="serviceJobId">The service job identifier.</param>
        public void DeleteMoreThanMax(int serviceJobId)
        {
            int historyCount;
            ServiceJobService serviceJobService = new ServiceJobService((RockContext)this.Context);
            ServiceJob        serviceJob        = serviceJobService.Get(serviceJobId);

            historyCount = serviceJob.HistoryCount;

            historyCount = historyCount <= 0 ? historyCount = 100 : historyCount;
            var matchingServiceJobs    = this.AsNoFilter().Where(a => a.ServiceJobId == serviceJobId).OrderByDescending(a => a.StartDateTime);
            var serviceJobsMoreThanMax = matchingServiceJobs.Skip(historyCount).ToArray();

            for (int i = 0; i < serviceJobsMoreThanMax.Count(); i++)
            {
                this.Delete(serviceJobsMoreThanMax[i]);
            }

            this.Context.SaveChanges();
        }
        /// <summary>
        /// Handles the Click event of the btnSave 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 btnSave_Click( object sender, EventArgs e )
        {
            ServiceJob job;
            ServiceJobService jobService = new ServiceJobService();

            int jobId = int.Parse( hfId.Value );

            if ( jobId == 0 )
            {
                job = new ServiceJob();
                jobService.Add( job, CurrentPersonId );
            }
            else
            {
                job = jobService.Get( jobId );
            }

            job.Name = tbName.Text;
            job.Description = tbDescription.Text;
            job.IsActive = cbActive.Checked;
            job.Assembly = tbAssembly.Text;
            job.Class = tbClass.Text;
            job.NotificationEmails = tbNotificationEmails.Text;
            job.NotificationStatus = (JobNotificationStatus)int.Parse( drpNotificationStatus.SelectedValue );
            job.CronExpression = tbCronExpression.Text;

            if ( !job.IsValid )
            {
                // Controls will render the error messages
                return;
            }

            RockTransactionScope.WrapTransaction( () =>
                {
                    jobService.Save( job, CurrentPersonId );
                } );

            BindGrid();
            pnlDetails.Visible = false;
            pnlGrid.Visible = true;
        }
        /// <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
            {
                LogMessage( APP_LOG_FILENAME, "Application Starting..." );

                DateTime startDateTime = RockDateTime.Now;
                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() )
                {
                    //// 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
                    LoadCacheObjects( rockContext );

                    // Run any plugin migrations
                    MigratePlugins( rockContext );

                    if ( System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment )
                    {
                        try
                        {
                            new AttributeService( rockContext ).Get( 0 );
                            System.Diagnostics.Debug.WriteLine( string.Format( "ConnectToDatabase - {0} ms", ( RockDateTime.Now - startDateTime ).TotalMilliseconds ) );
                            startDateTime = RockDateTime.Now;
                        }
                        catch
                        {
                            // Intentionally Blank
                        }
                    }

                    RegisterRoutes( rockContext, RouteTable.Routes );

                    // Configure Rock Rest API
                    GlobalConfiguration.Configure( Rock.Rest.WebApiConfig.Register );

                    if ( System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment )
                    {
                        System.Diagnostics.Debug.WriteLine( string.Format( "LoadCacheObjects - {0} ms", ( RockDateTime.Now - startDateTime ).TotalMilliseconds ) );
                        startDateTime = RockDateTime.Now;
                    }

                    // 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();
                    }

                    // 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 Succesfully" );
            }
            catch (Exception ex)
            {
                SetError66();
                throw ( new Exception( "Error occurred during application startup", ex ) );
            }
        }
Beispiel #10
0
        /// <summary>
        /// Handles the Click event of the btnSave 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 btnSave_Click( object sender, EventArgs e )
        {
            ServiceJob job;
            var rockContext = new RockContext();
            ServiceJobService jobService = new ServiceJobService( rockContext );

            int jobId = int.Parse( hfId.Value );

            if ( jobId == 0 )
            {
                job = new ServiceJob();
                jobService.Add( job );
            }
            else
            {
                job = jobService.Get( jobId );
            }

            job.Name = tbName.Text;
            job.Description = tbDescription.Text;
            job.IsActive = cbActive.Checked;
            job.Class = ddlJobTypes.SelectedValue;
            job.NotificationEmails = tbNotificationEmails.Text;
            job.NotificationStatus = (JobNotificationStatus)int.Parse( ddlNotificationStatus.SelectedValue );
            job.CronExpression = tbCronExpression.Text;

            if ( !job.IsValid )
            {
                // Controls will render the error messages
                return;
            }

            rockContext.WrapTransaction( () =>
            {
                rockContext.SaveChanges();

                job.LoadAttributes( rockContext );
                Rock.Attribute.Helper.GetEditValues( phAttributes, job );
                job.SaveAttributeValues( rockContext );

            } );

            NavigateToParentPage();
        }
Beispiel #11
0
        /// <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();
        }
Beispiel #12
0
        /// <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();
        }
Beispiel #13
0
        /// <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>
        /// Handles the RunNow event of the gScheduledJobs control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param>
        protected void gScheduledJobs_RunNow( object sender, RowEventArgs e )
        {
            var job = new ServiceJobService( new RockContext() ).Get( e.RowKeyId );
            if ( job != null )
            {
                var transaction = new Rock.Transactions.RunJobNowTransaction( job.Id );

                // Process the transaction on another thread
                System.Threading.Tasks.Task.Run( () => transaction.Execute() );

                mdGridWarning.Show( string.Format( "The '{0}' job has been started.", job.Name ), ModalAlertType.Information );

                // wait a split second for the job to start so that the grid will show the status (if it changed)
                System.Threading.Thread.Sleep( 250 );
            }

            BindGrid();
        }
        /// <summary>
        /// Shows the detail.
        /// </summary>
        /// <param name="serviceJobId">The service job identifier.</param>
        public void ShowDetail( int serviceJobId )
        {
            pnlDetails.Visible = true;
            LoadDropDowns();

            // Load depending on Add(0) or Edit
            ServiceJob job = null;
            if ( !serviceJobId.Equals( 0 ) )
            {
                job = new ServiceJobService( new RockContext() ).Get( serviceJobId );
                lActionTitle.Text = ActionTitle.Edit( ServiceJob.FriendlyTypeName ).FormatAsHtmlTitle();
                pdAuditDetails.SetEntity( job, ResolveRockUrl( "~" ) );
            }

            if ( job == null )
            {
                job = new ServiceJob { Id = 0, IsActive = true };
                lActionTitle.Text = ActionTitle.Add( ServiceJob.FriendlyTypeName ).FormatAsHtmlTitle();
                // hide the panel drawer that show created and last modified dates
                pdAuditDetails.Visible = false;
            }

            hfId.Value = job.Id.ToString();
            tbName.Text = job.Name;
            tbDescription.Text = job.Description;
            cbActive.Checked = job.IsActive.HasValue ? job.IsActive.Value : false;
            ddlJobTypes.SelectedValue = job.Class;
            tbNotificationEmails.Text = job.NotificationEmails;
            ddlNotificationStatus.SetValue( (int)job.NotificationStatus );
            tbCronExpression.Text = job.CronExpression;

            if (job.Id == 0)
            {
                job.Class = ddlJobTypes.SelectedValue;
                lCronExpressionDesc.Visible = false;
                lLastStatusMessage.Visible = false;
            }
            else
            {
                lCronExpressionDesc.Text = ExpressionDescriptor.GetDescription( job.CronExpression, new Options { ThrowExceptionOnParseError = false } );
                lCronExpressionDesc.Visible = true;

                lLastStatusMessage.Text = job.LastStatusMessage.ConvertCrLfToHtmlBr();
                lLastStatusMessage.Visible = true;
            }

            job.LoadAttributes();
            phAttributes.Controls.Clear();
            Rock.Attribute.Helper.AddEditControls( job, phAttributes, true, BlockValidationGroup );

            // render UI based on Authorized and IsSystem
            bool readOnly = false;

            nbEditModeMessage.Text = string.Empty;
            if ( !IsUserAuthorized( Authorization.EDIT ) )
            {
                readOnly = true;
                nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( ServiceJob.FriendlyTypeName );
            }

            if ( job.IsSystem )
            {
                readOnly = true;
                nbEditModeMessage.Text = EditModeMessage.ReadOnlySystem( ServiceJob.FriendlyTypeName );
            }

            if ( readOnly )
            {
                lActionTitle.Text = ActionTitle.View( ServiceJob.FriendlyTypeName ).FormatAsHtmlTitle();
                btnCancel.Text = "Close";
                Rock.Attribute.Helper.AddDisplayControls( job, phAttributesReadOnly );
                phAttributesReadOnly.Visible = true;
                phAttributes.Visible = false;
                tbCronExpression.Text = job.CronExpression;
            }

            tbName.ReadOnly = readOnly;
            tbDescription.ReadOnly = readOnly;
            cbActive.Enabled = !readOnly;
            ddlJobTypes.Enabled = !readOnly;
            tbNotificationEmails.ReadOnly = readOnly;
            ddlNotificationStatus.Enabled = !readOnly;
            tbCronExpression.ReadOnly = readOnly;

            btnSave.Visible = !readOnly;
        }
Beispiel #16
0
        /// <summary>
        /// Handles the Delete event of the grdScheduledJobs control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RowEventArgs" /> instance containing the event data.</param>
        protected void gScheduledJobs_Delete( object sender, RowEventArgs e )
        {
            RockTransactionScope.WrapTransaction( () =>
            {
                var jobService = new ServiceJobService();
                ServiceJob job = jobService.Get( (int)e.RowKeyValue );

                string errorMessage;
                if ( !jobService.CanDelete( job, out errorMessage ) )
                {
                    mdGridWarning.Show( errorMessage, ModalAlertType.Information );
                    return;
                }

                jobService.Delete( job, CurrentPersonId );
                jobService.Save( job, CurrentPersonId );
            } );

            BindGrid();
        }
Beispiel #17
0
        /// <summary>
        /// Called by the <see cref="IScheduler"/> after a <see cref="IJobDetail"/>
        /// has been executed, and before the associated <see cref="Quartz.Spi.IOperableTrigger"/>'s
        /// <see cref="Quartz.Spi.IOperableTrigger.Triggered"/> method has been called.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="jobException"></param>
        public void JobWasExecuted( IJobExecutionContext context, JobExecutionException jobException )
        {
            StringBuilder message = new StringBuilder();
            bool sendMessage = false;

            // get job type id
            int jobId = Convert.ToInt16( context.JobDetail.Description );

            // load job
            var rockContext = new RockContext();
            var jobService = new ServiceJobService( rockContext );
            var job = jobService.Get( jobId );

            // format the message
            message.Append( string.Format( "The job {0} ran for {1} seconds on {2}.  Below is the results:<p>", job.Name, context.JobRunTime.TotalSeconds, context.FireTimeUtc.Value.DateTime.ToLocalTime() ) );

            // if noticiation staus is all set flag to send message
            if ( job.NotificationStatus == JobNotificationStatus.All )
            {
                sendMessage = true;
            }

            // set last run date
            job.LastRunDateTime = RockDateTime.Now; // context.FireTimeUtc.Value.DateTime.ToLocalTime();

            // set run time
            job.LastRunDurationSeconds = Convert.ToInt32( context.JobRunTime.TotalSeconds );

            // set the scheduler name
            job.LastRunSchedulerName = context.Scheduler.SchedulerName;

            // determine if an error occured
            if ( jobException == null )
            {
                job.LastSuccessfulRunDateTime = job.LastRunDateTime;
                job.LastStatus = "Success";
                if ( context.Result is string )
                {
                    job.LastStatusMessage = context.Result as string;
                }

                message.Append( "Result: Success" );

                // determine if message should be sent
                if ( job.NotificationStatus == JobNotificationStatus.Success )
                {
                    sendMessage = true;
                }
            }
            else
            {
                Exception exceptionToLog = jobException;

                // drill down to the interesting exception
                while ( exceptionToLog is Quartz.SchedulerException && exceptionToLog.InnerException != null )
                {
                    exceptionToLog = exceptionToLog.InnerException;
                }

                // log the exception to the database
                ExceptionLogService.LogException( exceptionToLog, null );

                var summaryException = exceptionToLog;

                // put the exception into the status
                job.LastStatus = "Exception";

                AggregateException aggregateException = summaryException as AggregateException;
                if ( aggregateException != null && aggregateException.InnerExceptions != null && aggregateException.InnerExceptions.Count == 1 )
                {
                    // if it's an aggregate, but there is only one, convert it to a single exception
                    summaryException = aggregateException.InnerExceptions[0];
                    aggregateException = null;
                }

                if ( aggregateException != null )
                {
                    var firstException = aggregateException.InnerExceptions.First();
                    job.LastStatusMessage = "One or more exceptions occurred. First Exception: " + firstException.Message;
                    summaryException = firstException;
                }
                else
                {
                    job.LastStatusMessage = summaryException.Message;
                }

                message.Append( "Result: Exception<p>Message:<br>" + job.LastStatusMessage );

                if ( summaryException.InnerException != null )
                {
                    job.LastStatusMessage += " (" + summaryException.InnerException.Message + ")";
                    message.Append( "<p>Inner Exception:<br>" + summaryException.InnerException.Message );
                }

                if ( job.NotificationStatus == JobNotificationStatus.Error )
                {
                    sendMessage = true;
                }
            }

            rockContext.SaveChanges();

            // send notification
            if ( sendMessage )
            {
                // TODO: implement email send once it's available
            }
        }
        /// <summary>
        /// Shows the detail.
        /// </summary>
        /// <param name="itemKey">The item key.</param>
        /// <param name="itemKeyValue">The item key value.</param>
        public void ShowDetail( string itemKey, int itemKeyValue )
        {
            // return if unexpected itemKey
            if ( itemKey != "serviceJobId" )
            {
                return;
            }

            pnlDetails.Visible = true;
            LoadDropDowns();

            // Load depending on Add(0) or Edit
            ServiceJob job;
            if ( !itemKeyValue.Equals( 0 ) )
            {
                job = new ServiceJobService( new RockContext() ).Get( itemKeyValue );
                lActionTitle.Text = ActionTitle.Edit( ServiceJob.FriendlyTypeName ).FormatAsHtmlTitle();
            }
            else
            {
                job = new ServiceJob { Id = 0, IsActive = true };
                lActionTitle.Text = ActionTitle.Add( ServiceJob.FriendlyTypeName ).FormatAsHtmlTitle();
            }

            hfId.Value = job.Id.ToString();
            tbName.Text = job.Name;
            tbDescription.Text = job.Description;
            cbActive.Checked = job.IsActive.HasValue ? job.IsActive.Value : false;
            ddlJobTypes.SelectedValue = job.Class;
            tbNotificationEmails.Text = job.NotificationEmails;
            ddlNotificationStatus.SetValue( (int)job.NotificationStatus );
            tbCronExpression.Text = job.CronExpression;

            if (job.Id == 0)
            {
                job.Class = ddlJobTypes.SelectedValue;
                lCronExpressionDesc.Visible = false;
            }
            else
            {
                lCronExpressionDesc.Text = ExpressionDescriptor.GetDescription( job.CronExpression );
                lCronExpressionDesc.Visible = true;
            }

            job.LoadAttributes();
            phAttributes.Controls.Clear();
            Rock.Attribute.Helper.AddEditControls( job, phAttributes, true );

            // render UI based on Authorized and IsSystem
            bool readOnly = false;

            nbEditModeMessage.Text = string.Empty;
            if ( !IsUserAuthorized( Authorization.EDIT ) )
            {
                readOnly = true;
                nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( ServiceJob.FriendlyTypeName );
            }

            if ( job.IsSystem )
            {
                readOnly = true;
                nbEditModeMessage.Text = EditModeMessage.ReadOnlySystem( ServiceJob.FriendlyTypeName );
            }

            if ( readOnly )
            {
                lActionTitle.Text = ActionTitle.View( ServiceJob.FriendlyTypeName ).FormatAsHtmlTitle();
                btnCancel.Text = "Close";
                Rock.Attribute.Helper.AddDisplayControls( job, phAttributesReadOnly );
                phAttributesReadOnly.Visible = true;
                phAttributes.Visible = false;
                tbCronExpression.Text = job.CronExpression;
            }

            tbName.ReadOnly = readOnly;
            tbDescription.ReadOnly = readOnly;
            cbActive.Enabled = !readOnly;
            ddlJobTypes.Enabled = !readOnly;
            tbNotificationEmails.ReadOnly = readOnly;
            ddlNotificationStatus.Enabled = !readOnly;
            tbCronExpression.ReadOnly = readOnly;

            btnSave.Visible = !readOnly;
        }
        /// <summary>
        /// Method that will be run at Rock startup
        /// </summary>
        public void OnStartup()
        {
            /* 10-01-2021 MDP
             *
             * In multi-server/cluster/web-farm Rock environments, only one of the servers should be running
             * these DataMigrationsStartups. To make sure that multiple servers don't run these, we'll
             * check if this is the server with RunJobsInIISContext enabled.
             *
             * If RunJobsInIISContext isn't enabled on this server, don't run these. However, if this
             * is a developer environment, we'll want to run these regardless of the RunJobsInIISContext setting.
             *
             */

            bool runJobsInContext = Convert.ToBoolean(ConfigurationManager.AppSettings["RunJobsInIISContext"]);

            if (!runJobsInContext)
            {
                // RunJobsInIISContext isn't enabled on this server, so don't run these DataMigrationsStartups unless
                // this is a developer environment
                if (!System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment)
                {
                    // RunJobsInIISContext isn't enabled, and this isn't a developer environment so exit without running DataMigrationsStartups.
                    return;
                }
            }

            List <Guid> runOnceJobGuids = new List <Guid>
            {
                SystemGuid.ServiceJob.DATA_MIGRATIONS_74.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_80.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_84.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_90_DISC.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_90.AsGuid(),
                        SystemGuid.ServiceJob.MIGRATE_HISTORY_SUMMARY_DATA.AsGuid(),
                        SystemGuid.ServiceJob.MIGRATE_ATTENDANCE_OCCURRENCE.AsGuid(),
                        SystemGuid.ServiceJob.MIGRATE_FAMILY_CHECKIN_IDS.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_90_SCHEDULEDTRANSACTIONNOTESTOHISTORY.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_100_ATTRIBUTEVALUE_VALUEASNUMERIC.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_100_SUNDAYDATE.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_103_SPIRITUAL_GIFTS.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_110_POPULATE_DATE_KEYS.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_110_COMMUNICATIONRECIPIENT_RESPONSECODE_INDEX.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_110_POPULATE_RELATED_DATAVIEW_ID.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_120_UPDATE_INTERACTION_INDEXES.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_120_ADD_COMMUNICATIONRECIPIENT_INDEX.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_120_ADD_COMMUNICATION_GET_QUEUED_INDEX.AsGuid(),

                /* MDP 07-22-2021
                 *
                 * NOTE: We intentionally are excluding SystemGuid.ServiceJob.DATA_MIGRATIONS_122_INTERACTION_PERSONAL_DEVICE_ID
                 * from DataMigrationStartup and will just wait for it to run at 2am.
                 * See https://app.asana.com/0/0/1199506067368201/f
                 *
                 */

                        SystemGuid.ServiceJob.DATA_MIGRATIONS_124_UPDATE_GROUP_SALUTATIONS.AsGuid(),
                        SystemGuid.ServiceJob.POST_INSTALL_DATA_MIGRATIONS.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_124_DECRYPT_FINANCIAL_PAYMENT_DETAILS.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_125_UPDATE_STEP_PROGRAM_COMPLETION.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_125_ADD_COMMUNICATION_SYSTEM_COMMUNICATION_ID_INDEX.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_127_REBUILD_GROUP_SALUTATIONS.AsGuid(),
                        SystemGuid.ServiceJob.DATA_MIGRATIONS_130_ADD_INTERACTION_INTERACTION_COMPONENT_ID_INDEX.AsGuid()
            };

            // run any of the above jobs if they still exist (they haven't run and deleted themselves)
            var runOnceJobIds = new Model.ServiceJobService(new Rock.Data.RockContext()).Queryable().Where(a => runOnceJobGuids.Contains(a.Guid)).Select(a => a.Id).ToList();

            // start a task that will run any incomplete RunOneJobs (one at a time)
            Task.Run(() =>
            {
                var rockContext = new Rock.Data.RockContext();
                var jobService  = new Rock.Model.ServiceJobService(rockContext);
                foreach (var runOnceJobId in runOnceJobIds)
                {
                    try
                    {
                        var job = jobService.Get(runOnceJobId);
                        jobService.RunNow(job, out _);
                    }
                    catch (Exception ex)
                    {
                        // this shouldn't happen since the jobService.RunNow catches and logs errors, but just in case
                        ExceptionLogService.LogException(ex);
                    }
                }
            });
        }
Beispiel #20
0
        /// <summary>
        /// Called by the <see cref="IScheduler"/> after a <see cref="IJobDetail"/>
        /// has been executed, and before the associated <see cref="Quartz.Spi.IOperableTrigger"/>'s
        /// <see cref="Quartz.Spi.IOperableTrigger.Triggered"/> method has been called.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="jobException"></param>
        public void JobWasExecuted( IJobExecutionContext context, JobExecutionException jobException )
        {
            StringBuilder message = new StringBuilder();
            bool sendMessage = false;
            
            // get job type id
            int jobId = Convert.ToInt16(context.JobDetail.Description);

            // load job
            ServiceJobService jobService = new ServiceJobService();
            ServiceJob job = jobService.Get(jobId);
            
            // format the message
            message.Append( String.Format( "The job {0} ran for {1} seconds on {2}.  Below is the results:<p>" , job.Name, context.JobRunTime.TotalSeconds, context.FireTimeUtc.Value.DateTime.ToLocalTime()) );

            // if noticiation staus is all set flag to send message
            if ( job.NotificationStatus == JobNotificationStatus.All )
                sendMessage = true;

            // set last run date
            job.LastRunDateTime = context.FireTimeUtc.Value.DateTime.ToLocalTime();

            // set run time
            job.LastRunDurationSeconds = Convert.ToInt32(context.JobRunTime.TotalSeconds);

            // set the scheduler name
            job.LastRunSchedulerName = context.Scheduler.SchedulerName;

            // determine if an error occured
            if ( jobException == null )
            {
                job.LastSuccessfulRunDateTime = job.LastRunDateTime;
                job.LastStatus = "Success";
                job.LastStatusMessage = "";
                
                message.Append( "Result: Success" );

                // determine if message should be sent
                if ( job.NotificationStatus == JobNotificationStatus.Success )
                    sendMessage = true;
            }
            else
            {
                // put the exception into the status
                job.LastStatus = "Exception";
                job.LastStatusMessage = jobException.Message;

                message.Append( "Result: Exception<p>Message:<br>" + jobException.Message );

                if ( jobException.InnerException != null ) {
                    job.LastStatusMessage += " Inner Exception: " + jobException.InnerException.Message;
                    message.Append( "<p>Inner Exception:<br>" + jobException.InnerException.Message );
                }

                if ( job.NotificationStatus == JobNotificationStatus.Error )
                    sendMessage = true;
            }

            jobService.Save( job, null );

            // send notification
            if ( sendMessage )
            {
                // TODO: implement email send once it's available 
            }


        }
Beispiel #21
0
        /// <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
            {
                DateTime startDateTime = RockDateTime.Now;

                if ( System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment )
                {
                    System.Diagnostics.Debug.WriteLine( string.Format( "Application_Start: {0}", RockDateTime.Now.ToString( "hh:mm:ss.FFF" ) ) );
                }

                // Temporary code for v1.0.9 to delete payflowpro files in old location (The current update is not able to delete them, but 1.0.9 installs a fix for that)
                // This should be removed after 1.0.9
                try
                {
                    string physicalFile = System.Web.HttpContext.Current.Server.MapPath( @"~\Plugins\Payflow_dotNET.dll" );
                    if ( System.IO.File.Exists( physicalFile ) )
                    {
                        System.IO.File.Delete( physicalFile );
                    }
                    physicalFile = System.Web.HttpContext.Current.Server.MapPath( @"~\Plugins\Rock.PayFlowPro.dll" );
                    if ( System.IO.File.Exists( physicalFile ) )
                    {
                        System.IO.File.Delete( physicalFile );
                    }
                }
                catch
                {
                    // Intentionally Blank
                }

                // Get a db context
                var rockContext = new RockContext();

                //// 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 );

                if ( System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment )
                {
                    try
                    {
                        new AttributeService( rockContext ).Get( 0 );
                        System.Diagnostics.Debug.WriteLine( string.Format( "ConnectToDatabase - {0} ms", ( RockDateTime.Now - startDateTime ).TotalMilliseconds ) );
                        startDateTime = RockDateTime.Now;
                    }
                    catch
                    {
                        // Intentionally Blank
                    }
                }

                RegisterRoutes( rockContext, RouteTable.Routes );

                // Preload the commonly used objects
                LoadCacheObjects( rockContext );
                if ( System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment )
                {
                    System.Diagnostics.Debug.WriteLine( string.Format( "LoadCacheObjects - {0} ms", ( RockDateTime.Now - startDateTime ).TotalMilliseconds ) );
                    startDateTime = RockDateTime.Now;
                }

                // 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();

                GlobalConfiguration.Configuration.EnableCors( new Rock.Rest.EnableCorsFromOriginAttribute() );

                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>
        /// Handles the Click event of the btnSave 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 btnSave_Click( object sender, EventArgs e )
        {
            try
            {
                ExpressionDescriptor.GetDescription( tbCronExpression.Text );
            }
            catch (Exception ex)
            {
                tbCronExpression.ShowErrorMessage( "Invalid Cron Expression: " + ex.Message );
                return;
            }

            ServiceJob job;
            var rockContext = new RockContext();
            ServiceJobService jobService = new ServiceJobService( rockContext );

            int jobId = int.Parse( hfId.Value );

            if ( jobId == 0 )
            {
                job = new ServiceJob();
                jobService.Add( job );
            }
            else
            {
                job = jobService.Get( jobId );
            }

            job.Name = tbName.Text;
            job.Description = tbDescription.Text;
            job.IsActive = cbActive.Checked;

            if (job.Class != ddlJobTypes.SelectedValue)
            {
                job.Class = ddlJobTypes.SelectedValue;

                //// if the Class has changed, the current Assembly value might not match,
                //// so set the Assembly to null to have Rock figure it out automatically
                job.Assembly = null;
            }

            job.NotificationEmails = tbNotificationEmails.Text;
            job.NotificationStatus = (JobNotificationStatus)int.Parse( ddlNotificationStatus.SelectedValue );
            job.CronExpression = tbCronExpression.Text;

            if ( !job.IsValid )
            {
                // Controls will render the error messages
                return;
            }

            rockContext.WrapTransaction( () =>
            {
                rockContext.SaveChanges();

                job.LoadAttributes( rockContext );
                Rock.Attribute.Helper.GetEditValues( phAttributes, job );
                job.SaveAttributeValues( rockContext );

            } );

            NavigateToParentPage();
        }
Beispiel #23
0
        /// <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 )
            {
                System.Diagnostics.Debug.WriteLine( string.Format( "Application_Start: {0}", DateTime.Now.ToString("hh:mm:ss.FFF" ) ));
            }

            // 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, null );
                }

            }
            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 );
            }

            if ( System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment )
            {
                new AttributeService().Get( 0 );
                System.Diagnostics.Debug.WriteLine( string.Format( "ConnectToDatabase - Connected: {0}", DateTime.Now.ToString( "hh:mm:ss.FFF" ) ) );
            }

            // Preload the commonly used objects
            LoadCacheObjects();
            if ( System.Web.Hosting.HostingEnvironment.IsDevelopmentEnvironment )
            {
                System.Diagnostics.Debug.WriteLine( string.Format( "LoadCacheObjects - Done: {0}", DateTime.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();
                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>
        /// Handles the SelectedIndexChanged event of the ddlJobTypes 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 ddlJobTypes_SelectedIndexChanged( object sender, EventArgs e )
        {
            ServiceJob job;
            var itemId = PageParameter( "serviceJobId" ).AsInteger();
            if ( itemId == 0 )
            {
                job = new ServiceJob { Id = 0, IsActive = true };
            }
            else
            {
                job = new ServiceJobService( new RockContext() ).Get( itemId );
            }

            job.Class = ddlJobTypes.SelectedValue;
            job.LoadAttributes();
            phAttributes.Controls.Clear();
            Rock.Attribute.Helper.AddEditControls( job, phAttributes, true, BlockValidationGroup );
        }
        /// <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 );
            }
        }
Beispiel #26
0
        /// <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();

                // If not migrating, set up view cache to speed up startup (Not supported when running migrations).
                var fileInfo = new FileInfo( Server.MapPath( "~/App_Data/Run.Migration" ) );
                if ( !fileInfo.Exists )
                {
                    RockInteractiveViews.SetViewFactory( Server.MapPath( "~/App_Data/RockModelViews.xml" ) );
                }

                // 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();
                    }

                    // set the encryption protocols that are permissible for external SSL connections
                    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12;

                    // 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 ) );
            }

            // Update attributes for new workflow actions
            new Thread( () =>
            {
                Rock.Workflow.ActionContainer.Instance.UpdateAttributes();
            } ).Start();

            // compile less files
            new Thread( () =>
            {
                Thread.CurrentThread.IsBackground = true;
                RockTheme.CompileAll();

            } ).Start();
        }
        /// <summary>
        /// Schedules the Job to run immediately using the Quartz Scheduler
        /// and waits for the job to finish.
        /// Returns <c>false</c> with an <c>out</c> <paramref name="errorMessage"/> if the job is already running as a RunNow job or if an exception occurs.
        /// NOTE: This will take at least 10 seconds to ensure the Quartz scheduler successfully started the job, plus any additional time that might
        /// still be needed to complete the job.
        /// </summary>
        /// <param name="job">The job.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        public bool RunNow(ServiceJob job, out string errorMessage)
        {
            // use a new RockContext instead of using this.Context so we can SaveChanges without affecting other RockContext's with pending changes.
            var rockContext = new RockContext();

            errorMessage = string.Empty;
            try
            {
                // create a scheduler specific for the job
                var scheduleConfig = new NameValueCollection();

                var jobId = job.Id;

                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
                    errorMessage = "Job already running as a RunNow job";
                    return(false);
                }

                // Check if another scheduler is running this job
                try
                {
                    var otherSchedulers = new StdSchedulerFactory()
                                          .AllSchedulers
                                          .Where(s => s.SchedulerName != runNowSchedulerName);

                    foreach (var scheduler in otherSchedulers)
                    {
                        var isAlreadyRunning = scheduler.GetCurrentlyExecutingJobs()
                                               .Where(j =>
                                                      j.JobDetail.Description == jobId.ToString() &&
                                                      j.JobDetail.ConcurrentExectionDisallowed)
                                               .Any();

                        if (isAlreadyRunning)
                        {
                            // A job with that Id is already running and ConcurrentExectionDisallowed is true
                            errorMessage = $" Scheduler '{scheduler.SchedulerName}' is already executing job Id '{jobId}' (name: {job.Name})";
                            System.Diagnostics.Debug.WriteLine($"{RockDateTime.Now.ToString()} {errorMessage}");
                            return(false);
                        }
                    }
                }
                catch
                {
                    // Was blank in the RunJobNowTransaction (intentional?)
                }

                // create the quartz job and trigger
                var jobDetail  = new ServiceJobService(rockContext).BuildQuartzJob(job);
                var jobDataMap = jobDetail.JobDataMap;

                if (jobDataMap != 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(jobDataMap.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 scheduler to start the job.
                // If we don't do this, the scheduler might Shutdown thinking there are no running jobs
                Task.Delay(10 * 1000).Wait();

                // stop the scheduler when done with job
                sched.Shutdown(true);

                return(true);
            }
            catch (Exception ex)
            {
                // create a friendly error message
                ExceptionLogService.LogException(ex, null);
                errorMessage          = string.Format("Error doing a 'Run Now' on job: {0}. \n\n{2}", job.Name, job.Assembly, ex.Message);
                job.LastStatusMessage = errorMessage;
                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();

                return(false);
            }
        }
Beispiel #28
0
        /// <summary>
        /// Binds the scheduled jobs.
        /// </summary>
        private void BindGrid()
        {
            var jobService = new ServiceJobService();
            SortProperty sortProperty = gScheduledJobs.SortProperty;

            if ( sortProperty != null )
            {
                gScheduledJobs.DataSource = jobService.GetAllJobs().Sort( sortProperty ).ToList();
            }
            else
            {
                gScheduledJobs.DataSource = jobService.GetAllJobs().OrderByDescending( a => a.LastRunDateTime ).ToList();
            }
            
            gScheduledJobs.DataBind();
        }
        /// <summary>
        /// Handles the RunNow event of the gScheduledJobs control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param>
        protected void gScheduledJobs_RunNow( object sender, RowEventArgs e )
        {
            var job = new ServiceJobService( new RockContext() ).Get( e.RowKeyId );
            if ( job != null )
            {
                var transaction = new Rock.Transactions.RunJobNowTransaction( job.Id );
                Rock.Transactions.RockQueue.TransactionQueue.Enqueue( transaction );

                mdGridWarning.Show( string.Format( "The '{0}' job has been triggered to run and will start within the next two minutes ( during the next transaction cycle ).", job.Name ), ModalAlertType.Information );
            }

            BindGrid();
        }
Beispiel #30
0
        /// <summary>
        /// Called by the <see cref="IScheduler"/> when a <see cref="IJobDetail"/>
        /// is about to be executed (an associated <see cref="ITrigger"/>
        /// has occurred).
        /// <para>
        /// This method will not be invoked if the execution of the Job was vetoed
        /// by a <see cref="ITriggerListener"/>.
        /// </para>
        /// </summary>
        /// <param name="context"></param>
        /// <seealso cref="JobExecutionVetoed(IJobExecutionContext)"/>
        public void JobToBeExecuted( IJobExecutionContext context )
        {
            StringBuilder message = new StringBuilder();

            // get job type id
            int jobId = context.JobDetail.Description.AsInteger();

            // load job
            var rockContext = new RockContext();
            var jobService = new ServiceJobService( rockContext );
            var job = jobService.Get( jobId );

            if (job != null && job.Guid != Rock.SystemGuid.ServiceJob.JOB_PULSE.AsGuid())
            {
                job.LastStatus = "Running";
                job.LastStatusMessage = "Started at " + RockDateTime.Now.ToString();
                rockContext.SaveChanges();
            }
        }
        /// <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();
        }