/// <summary>
        /// Cancels a running workflow.
        /// </summary>
        /// <remarks>
        /// This happened because of an explicit cancel request by a user.
        /// </remarks>
        public Guid CancelJob(Job job)
        {
            EnsureNotStopping();

            JobInstance ji;
            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.ContextGuid = contextGuid;
                context.JobGuid = job.Guid;

                ji = LoadJobInstance(context, job);

                // Update registry
                ji.JobExecutionStatus = JobExecutionState.Cancelling;
                ji.Save();
            }

            return CancelWorkflow(ji.WorkflowInstanceId);
        }
 /// <summary>
 /// Do bookkeeping required when a workflow starts
 /// </summary>
 /// <param name="wfapp"></param>
 private void RegisterWorkflow(Job job, WorkflowApplication wfapp)
 {
     lock (syncRoot)
     {
         workflows.Add(wfapp.Id, new WorkflowDetails()
         {
             Job = job,
             WorkflowApplication = wfapp,
         });
     }
 }
        private void SaveWorkflowParameters(Job job, IDictionary<string, object> outputs)
        {
            // Load job data from the registry
            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.ContextGuid = contextGuid;
                context.JobGuid = job.Guid;

                JobInstance ji = LoadJobInstance(context, job);

                foreach (var name in outputs.Keys)
                {
                    ji.Parameters[name].SetValue(outputs[name]);
                }

                ji.Save();
            }
        }
Exemple #4
0
        /// <summary>
        /// Instructes the workflow host to start a job.
        /// </summary>
        /// <param name="jobGuid"></param>
        /// <returns></returns>
        public Guid PrepareStartJob(Job job)
        {
            lastTimeActive = DateTime.Now;
            return workflowHost.PrepareStartJob(job);

            // *** TODO: handle initialization errors here
        }
        /// <summary>
        /// Starts a job workflow
        /// </summary>
        /// <param name="wftype"></param>
        /// <param name="par"></param>
        /// <returns></returns>
        private Guid PrepareStartWorkflow(Job job, Dictionary<string, object> par)
        {
            var wftype = GetWorkflowType(job);
            var wfapp = CreateWorkflowApplication(wftype, par);

            RegisterWorkflow(job, wfapp);
            return wfapp.Id;
        }
Exemple #6
0
        /// <summary>
        /// Returns an AppDomainHost to run the job.
        /// </summary>
        /// <remarks>
        /// Either an existing AppDomainHost is returned that has the
        /// required assembly, or a new AppDomainHost is created.
        /// </remarks>
        /// <param name="job"></param>
        /// <returns></returns>
        private AppDomainHost GetOrCreateAppDomainHost(Job job)
        {
            AppDomain ad;
            Components.AppDomainManager.Instance.GetAppDomainForType(job.WorkflowTypeName, true, out ad);

            if (!appDomains.ContainsKey(ad.Id))
            {
                // New app domain, create host
                var adh = new AppDomainHost(ad, contextGuid);
                adh.WorkflowEvent += new EventHandler<HostEventArgs>(adh_WorkflowEvent);

                appDomains.Add(ad.Id, adh);

                adh.Start(Scheduler, interactive);

                return adh;
            }
            else
            {
                // Old app domain, return existing host
                return appDomains[ad.Id];
            }
        }
Exemple #7
0
        /// <summary>
        /// Queries the registry for new jobs to schedule
        /// </summary>
        private void PollNewJobs()
        {
            List<Job> temp = new List<Job>();

            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.ContextGuid = contextGuid;

                foreach (var queue in Cluster.Queues.Values)
                {
                    var qi = new QueueInstance(context);
                    qi.Guid = queue.Guid;
                    qi.Load();

                    var ji = qi.GetNextJobInstance();

                    if (ji != null)
                    {
                        var user = new User(context);
                        user.Guid = ji.UserGuidOwner;
                        user.Load();

                        var job = new Job()
                        {
                            Guid = ji.Guid,
                            JobID = ji.JobID,
                            UserGuid = user.Guid,
                            UserName = user.Name,
                            QueueGuid = ji.ParentReference.Guid,
                            WorkflowTypeName = ji.WorkflowTypeName,
                        };

                        if ((ji.JobExecutionStatus & JobExecutionState.Scheduled) != 0)
                        {
                            job.Status = JobStatus.Starting;
                            ji.JobExecutionStatus = JobExecutionState.Starting;
                        }
                        else if ((ji.JobExecutionStatus & JobExecutionState.Persisted) != 0)
                        {
                            // Save cancel requested flag here
                            ji.JobExecutionStatus ^= JobExecutionState.Persisted;
                            ji.JobExecutionStatus |= JobExecutionState.Starting;

                            job.Status = JobStatus.Resuming;
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }

                        ji.Save();

                        lock (queue)
                        {
                            queue.Jobs.Add(job.Guid, job);
                        }

                        temp.Add(job);
                    }
                }
            }

            foreach (var job in temp)
            {
                StartOrResumeJob(job);
            }
        }
        /// <summary>
        /// Sets up a new workflow and starts the new job
        /// </summary>
        /// <param name="jobGuid"></param>
        /// <returns></returns>
        public Guid PrepareStartJob(Job job)
        {
            EnsureNotStopping();

            // Load job data from the registry
            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.ContextGuid = contextGuid;
                context.JobGuid = job.Guid;

                JobInstance ji = LoadJobInstance(context, job);

                // Deserialize parameters
                Dictionary<string, object> pars = new Dictionary<string, object>();
                foreach (var par in ji.Parameters.Values)
                {
                    if ((par.Direction & JobParameterDirection.In) != 0)
                    {
                        pars.Add(par.Name, ji.Parameters[par.Name].GetValue());
                    }
                }

                // Set default parameters
                pars.Add("UserGuid", ji.UserGuidOwner);
                pars.Add("JobGuid", ji.Guid);

                // Start the workflow
                Guid wfguid = PrepareStartWorkflow(job, pars);

                // Update registry
                ji.DateStarted = DateTime.Now;
                ji.WorkflowInstanceId = wfguid;
                ji.JobExecutionStatus = JobExecutionState.Executing;

                ji.Save();

                return wfguid;
            }
        }
        public void RunJob(Job job)
        {
            EnsureNotStopping();

            lock (syncRoot)
            {
                workflows[job.WorkflowInstanceId].WorkflowApplication.Run();
            }
        }
        public Guid PersistJob(Job job)
        {
            EnsureNotStopping();

            JobInstance ji;
            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.ContextGuid = contextGuid;
                context.JobGuid = job.Guid;

                ji = LoadJobInstance(context, job);

                // Update registry
                ji.JobExecutionStatus = JobExecutionState.Persisting;
                ji.Save();
            }

            // For some reason, unloading happens synchronously so to avoid deadlock with
            // the previous registry update, this has to be called outside the context
            return PersistWorkflow(ji.WorkflowInstanceId);
        }
        /// <summary>
        /// Resumes a previously persisted workflow
        /// </summary>
        /// <param name="jobGuid"></param>
        /// <returns></returns>
        public Guid PrepareResumeJob(Job job)
        {
            EnsureNotStopping();

            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.ContextGuid = contextGuid;
                context.JobGuid = job.Guid;

                JobInstance ji = LoadJobInstance(context, job);

                // Load assembly and create workflow instance
                Type wftype = Type.GetType(ji.WorkflowTypeName);

                // Resume the workflow
                Guid wfguid = PrepareResumeWorkflow(job, ji.WorkflowInstanceId);

                // Update registry
                ji.JobExecutionStatus = JobExecutionState.Executing;
                ji.Save();

                return wfguid;
            }
        }
Exemple #12
0
 /// <summary>
 /// Instructs the workflow host to cancel a
 /// running job.
 /// </summary>
 /// <param name="workflowInstanceId"></param>
 public void CancelJob(Job job)
 {
     lastTimeActive = DateTime.Now;
     workflowHost.CancelJob(job);
 }
Exemple #13
0
 /// <summary>
 /// Instructs the workflow host to cancel the job and mark it as timed-out.
 /// </summary>
 /// <param name="job"></param>
 public void TimeOutJob(Job job)
 {
     lastTimeActive = DateTime.Now;
     workflowHost.TimeOutJob(job);
 }
Exemple #14
0
 public void RunJob(Job job)
 {
     lastTimeActive = DateTime.Now;
     workflowHost.RunJob(job);
 }
Exemple #15
0
        private void CancelOrTimeOutJob(Job job, bool timeout)
        {
            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.JobGuid = job.Guid;
                context.ContextGuid = contextGuid;

                var ji = new JobInstance(context);
                ji.Guid = job.Guid;
                ji.Load();

                // Update registry
                ji.JobExecutionStatus = JobExecutionState.Cancelling;

                ji.Save();
            }

            // Update job status
            if (timeout)
            {
                job.Status = JobStatus.TimedOut;
                appDomains[job.AppDomainID].TimeOutJob(job);
            }
            else
            {
                job.Status = JobStatus.Cancelled;
                appDomains[job.AppDomainID].CancelJob(job);
            }
        }
        private Type GetWorkflowType(Job job)
        {
            // Implicitely load the assembly.

            // TODO: If this fails, assembly loading failure
            // is the cause. Check ReflectionHelperInternal event handlers.
            Type wftype = Type.GetType(job.WorkflowTypeName);

            if (wftype == null)
            {
                throw new TypeLoadException(ExceptionMessages.ErrorLoadingWorkflowType);
            }

            return wftype;
        }
Exemple #17
0
        /// <summary>
        /// Finished the execution of a job and records the results in the registry.
        /// </summary>
        /// <param name="workflowInstanceId"></param>
        /// <param name="eventType"></param>
        private void FinishJob(Job job, HostEventArgs e)
        {
            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.JobGuid = job.Guid;
                context.ContextGuid = contextGuid;

                JobInstance ji = new JobInstance(context);
                ji.Guid = job.Guid;
                ji.Load();

                // Update execution status, error message and finish time
                switch (e.EventType)
                {
                    case WorkflowEventType.Completed:
                        ji.JobExecutionStatus = JobExecutionState.Completed;
                        break;
                    case WorkflowEventType.Cancelled:
                        ji.JobExecutionStatus = JobExecutionState.Cancelled;
                        break;
                    case WorkflowEventType.TimedOut:
                        ji.JobExecutionStatus = JobExecutionState.TimedOut;
                        break;
                    case WorkflowEventType.Persisted:
                        ji.JobExecutionStatus = JobExecutionState.Persisted;
                        break;
                    case WorkflowEventType.Failed:
                        ji.JobExecutionStatus = JobExecutionState.Failed;
                        ji.ExceptionMessage = e.ExceptionMessage;
                        break;
                }

                // Update registry
                ji.DateFinished = DateTime.Now;
                ji.Save();

                ji.ReleaseLock(false);
                ji.RescheduleIfRecurring();

                // Do local bookkeeping
                lock (runningJobs)
                {
                    lock (Cluster.Queues[job.QueueGuid].Jobs)
                    {
                        Cluster.Queues[job.QueueGuid].Jobs.Remove(job.Guid);
                    }

                    runningJobs.Remove(job.WorkflowInstanceId);
                }

                if (interactive)
                {
                    Console.WriteLine("Finishing job: {0}", ji.Guid);
                }
            }
        }
        private JobInstance LoadJobInstance(Context context, Job job)
        {
            var ji = new JobInstance(context);
            ji.Guid = job.Guid;
            ji.Load();

            return ji;
        }
Exemple #19
0
        private void PersistJob(Job job)
        {
            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.JobGuid = job.Guid;
                context.ContextGuid = contextGuid;

                var ji = new JobInstance(context);
                ji.Guid = job.Guid;
                ji.Load();

                // Update registry
                ji.JobExecutionStatus = JobExecutionState.Persisting;

                ji.Save();
            }

            // Update job status
            job.Status = JobStatus.Persisted;

            appDomains[job.AppDomainID].PersistJob(job);
        }
        /// <summary>
        /// Resumes a previously persisted job workflow
        /// </summary>
        /// <param name="wftype"></param>
        /// <param name="par"></param>
        /// <param name="instanceId"></param>
        /// <returns></returns>
        private Guid PrepareResumeWorkflow(Job job, Guid instanceId)
        {
            var wftype = GetWorkflowType(job);
            var wfapp = CreateWorkflowApplication(wftype, null);

            wfapp.Load(instanceId);
            RegisterWorkflow(job, wfapp);

            return wfapp.Id;
        }
Exemple #21
0
        /// <summary>
        /// Starts a single job
        /// </summary>
        /// <param name="job"></param>
        private void StartOrResumeJob(Job job)
        {
            AppDomainHost adh = null;

            using (Context context = ContextManager.Instance.CreateContext(ConnectionMode.AutoOpen, TransactionMode.AutoCommit))
            {
                context.JobGuid = job.Guid;
                context.ContextGuid = contextGuid;

                JobInstance ji = new JobInstance(context);
                ji.Guid = job.Guid;
                ji.Load();

                // Lock the job, so noone else can pick it up
                ji.DateStarted = DateTime.Now;
                ji.ObtainLock();

                ji.Save();
            }

            // Schedule job in the appropriate app domain
            adh = GetOrCreateAppDomainHost(job);

            // Check if job is a new instance or previously persisted and
            // has to be resumed
            switch (job.Status)
            {
                case JobStatus.Starting:
                    if (interactive)
                    {
                        Console.WriteLine("Starting job: {0}", job.Guid);
                    }

                    job.WorkflowInstanceId = adh.PrepareStartJob(job);
                    break;
                case JobStatus.Resuming:
                    if (interactive)
                    {
                        Console.WriteLine("Resuming job: {0}", job.Guid);
                    }

                    job.WorkflowInstanceId = adh.PrepareResumeJob(job);
                    break;
                default:
                    throw new NotImplementedException();
            }

            // Update job status
            job.TimeStarted = DateTime.Now;
            job.Status = JobStatus.Executing;
            job.AppDomainID = adh.ID;

            // TODO: this has to happen before starting the job
            lock (runningJobs)
            {
                runningJobs.Add(job.WorkflowInstanceId, job);
            }

            adh.RunJob(job);
        }
Exemple #22
0
 /// <summary>
 /// Instructs the workflow host to persist and suspend a job.
 /// </summary>
 /// <param name="jobGuid"></param>
 public void PersistJob(Job job)
 {
     lastTimeActive = DateTime.Now;
     workflowHost.PersistJob(job);
 }