Exemple #1
0
        /// <summary>
        /// Creates a new background operation. The background operations runs the given method at given intervals. Must be separately started.
        /// </summary>
        /// <param name="name">The name of the operation.</param>
        /// <param name="method">The method to invoke at given intervals.</param>
        /// <returns>A new background operation, that is not yet started.</returns>
        public TaskQueueBackgroundOperation <TDirective> CreateBackgroundOperation <TDirective>
        (
            string name,
            Action <TaskProcessorJob, TDirective> method
        )
            where TDirective : TaskQueueDirective
        {
            TaskQueueBackgroundOperation <TDirective> backgroundOperation;

            lock (TaskQueueBackgroundOperationManager._lock)
            {
                if (this.BackgroundOperations.ContainsKey(name))
                {
                    throw new ArgumentException(
                              $"A background operation with the name {name} in queue {this.QueueId} could not be found.",
                              nameof(name));
                }

                // Create the background operation.
                backgroundOperation = new TaskQueueBackgroundOperation <TDirective>
                                      (
                    this,
                    name,
                    method,
                    this.CancellationTokenSource
                                      );

                // Add it to the dictionary.
                this.BackgroundOperations.Add(name, backgroundOperation);
            }

            // Return it.
            return(backgroundOperation);
        }
Exemple #2
0
        /// <summary>
        /// Handles when a job from a task requires processing.
        /// Note that all tasks/jobs in the queue use the same task type ID,
        /// so the directive <see cref="BackgroundOperationTaskQueueDirective.BackgroundOperationName"/>
        /// is used to identify which tasks should be executed by
        /// which background operation.
        /// </summary>
        /// <param name="job">The job to process.</param>
        protected virtual void ProcessJobHandler(TaskProcessorJob job)
        {
            // Sanity.
            if (null == job)
            {
                return;
            }

            // Ensure cancellation has not been requested.
            job.ThrowIfCancellationRequested();

            // Update the progress of the task in the task queue.
            this.TaskProcessor.UpdateTaskAsAssignedToProcessor(job);

            // Sanity.
            if (null == job.Data?.Value)
            {
                // This is an issue.  We have no way to decide what background operation should run it.  Die.
                SysUtils.ReportErrorToEventLog
                (
                    $"Job loaded with no application task (queue: {job.AppTaskQueueId}, task type: {job.AppTaskId})."
                );
                return;
            }

            // Deserialize the background directive.
            var backgroundOperationDirective = job.GetTaskQueueDirective <BackgroundOperationTaskQueueDirective>();

            if (null == backgroundOperationDirective)
            {
                // This is an issue.  We have no way to decide what background operation should run it.  Die.
                SysUtils.ReportErrorToEventLog
                (
                    $"Job loaded with no background operation name loaded (queue: {job.AppTaskQueueId}, task type: {job.AppTaskId})."
                );
                return;
            }

            // If we have a directive then extract it.
            var dir = backgroundOperationDirective.GetParsedInternalDirective();

            // If it is a broadcast directive, then was it generated on the same server?
            // If so then ignore.
            if (dir is BroadcastDirective broadcastDirective)
            {
                if (broadcastDirective.GeneratedFromGuid == TaskQueueBackgroundOperationManager.CurrentServer.ServerID)
                {
                    return;
                }
            }

            // Find the background operation to run.
            TaskQueueBackgroundOperation bo = null;

            lock (_lock)
            {
                if (false == this.BackgroundOperations.TryGetValue(backgroundOperationDirective.BackgroundOperationName, out bo))
                {
                    // We have no registered background operation to handle the callback.
                    SysUtils.ReportErrorToEventLog
                    (
                        $"No background operation found with name {backgroundOperationDirective.BackgroundOperationName}(queue: {job.AppTaskQueueId}, task type: {job.AppTaskId})."
                    );
                    return;
                }
            }

            // If it is recurring then use the ProcessingComplete event to schedule the next execution.
            if (bo.Recurring && bo.Interval.HasValue)
            {
                // Bind to the completed event ( called always ) of the job.
                // That way even if the job is canceled, fails, or finishes successfully
                // ...we always schedule the next run.
                job.ProcessingCompleted += (s, op)
                                           => this.RunOnce
                                           (
                    bo.Name,
                    DateTime.UtcNow.Add(bo.Interval.Value),
                    dir
                                           );
            }

            // Perform the action.
            try
            {
                // Delegate to the background operation.
                bo.RunJob(job, dir);
            }
            catch (Exception e)
            {
                // Exception.
                this.TaskProcessor.UpdateTaskInfo
                (
                    job.Data?.Value,
                    MFTaskState.MFTaskStateFailed,
                    e.Message,
                    false
                );
                // TODO: throw?
            }
        }