nopcommerce計划任務分析


對比了一下nopcommerce和orchard的計划任務,orchard的復雜的不是一點點,如果想拆下來自己用難度很大,搜索拆了orchard的lucene處理模塊,郵件隊列拆的discuznt和nopcommerce的結合,計划任務就拆nopcommerce的了,discuznt計划任務設計的沒nopcommerce的好。

1.nopcommerce的tasks結構如下:

IScheduleTaskService.cs 接口,這個主要是獲取數據庫里的任務信息,ScheduleTaskService.cs去實現它就可以了,當然需要在容器里注入一下。

ITask 這個接口比較特別但是很重要,所有的任務處理類都要實現里面唯一的Execute方法。執行計划任務時就需要通過反射來執行這個實現。

namespace Nop.Services.Tasks
{
    /// <summary>
    /// Interface that should be implemented by each task
    /// </summary>
    public partial interface ITask
    {
        /// <summary>
        /// Execute task
        /// </summary>
        void Execute();
    }
}

核心類之一:Task.cs,這個主要是處理任務的執行過程及執行過程類的結果處理。

private ITask CreateTask()
        {
            ITask task = null;
            if (this.Enabled)
            {
                var type2 = System.Type.GetType(this._type);
                if (type2 != null)
                {
                    task = Activator.CreateInstance(type2) as ITask;
                }
                //this._enabled = task != null;
            }
            return task;
        }

通過反射來找到編寫的計划任務類。例如下面的發送郵件的任務。

View Code
using System;
using Nop.Core.Infrastructure;
using Nop.Services.Logging;
using Nop.Services.Tasks;

namespace Nop.Services.Messages
{
    /// <summary>
    /// Represents a task for sending queued message 
    /// </summary>
    public partial class QueuedMessagesSendTask : ITask
    {

        /// <summary>
        /// Executes a task
        /// </summary>
        public void Execute()
        {
            var queuedEmailService = EngineContext.Current.Resolve<IQueuedEmailService>();
            var emailSender = EngineContext.Current.Resolve<IEmailSender>();

            var maxTries = 3;
            var queuedEmails = queuedEmailService.SearchEmails(null, null, null, null,
                true, maxTries, false, 0, 10000);
            foreach (var queuedEmail in queuedEmails)
            {
                var bcc = String.IsNullOrWhiteSpace(queuedEmail.Bcc) 
                            ? null 
                            : queuedEmail.Bcc.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                var cc = String.IsNullOrWhiteSpace(queuedEmail.CC) 
                            ? null 
                            : queuedEmail.CC.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                try
                {
                    emailSender.SendEmail(queuedEmail.EmailAccount, queuedEmail.Subject, queuedEmail.Body,
                       queuedEmail.From, queuedEmail.FromName, queuedEmail.To, queuedEmail.ToName, bcc, cc);

                    queuedEmail.SentOnUtc = DateTime.UtcNow;
                }
                catch (Exception exc)
                {
                    var logger = EngineContext.Current.Resolve<ILogger>();
                    logger.Error(string.Format("Error sending e-mail. {0}", exc.Message), exc);
                }
                finally
                {
                    queuedEmail.SentTries = queuedEmail.SentTries + 1;
                    queuedEmailService.UpdateQueuedEmail(queuedEmail);
                }
            }
        }
    }
}

執行完任務后需要將數據庫里的任務記錄狀態更改,主要是時間狀態變更。

核心執行方法:

        /// <summary>
        /// 執行任務
        /// </summary>
        public void Execute()
        {
            this._isRunning = true;
            try
            {
                var task = this.CreateTask();
                if (task != null)
                {
                    this._lastStartUtc = DateTime.UtcNow;
                    task.Execute();
                    this._lastEndUtc = this._lastSuccessUtc = DateTime.UtcNow;
                }
            }
            catch (Exception exc)
            {
                this._enabled = !this.StopOnError;
                this._lastEndUtc = DateTime.UtcNow;
                
                //log error
                var logger = EngineContext.Current.Resolve<ILogger>();
                logger.Error(string.Format("Error while running the '{0}' schedule task. {1}", this._name, exc.Message), exc);
            }
            
            try
            {
                //find current schedule task
                var scheduleTaskService = EngineContext.Current.Resolve<IScheduleTaskService>();
                var scheduleTask = scheduleTaskService.GetTaskByType(this._type);
                if (scheduleTask != null)
                {
                    scheduleTask.LastStartUtc = this.LastStartUtc;
                    scheduleTask.LastEndUtc = this.LastEndUtc;
                    scheduleTask.LastSuccessUtc = this.LastSuccessUtc;
                    scheduleTaskService.UpdateTask(scheduleTask);
                }
            }
            catch (Exception exc)
            {
                Debug.WriteLine(string.Format("Error saving schedule task datetimes. Exception: {0}", exc));
            }
            this._isRunning = false;
        }

 任務管理類:TaskManager.cs,主要負責任務的初始化,添加到線程列表,任務的開始和停止。需要在Global里初始化和開始任務,它會根據線程里的定時器自動讀取任務列表執行任務。

            //開始執行任務
            if (databaseInstalled)
            {
                TaskManager.Instance.Initialize();
                TaskManager.Instance.Start();
            }

任務線程管理類:TaskThread.cs,任務線程類,TaskManager將任務都添加到此線程管理類里,此線程管理主要負責判斷任務的執行狀態,線程執行間隔時間及調用任務執行的主方法Execute,通過Timer定時器實現定時自動運行。

主方法為:

        private void Run()
        {
            if (_seconds <=0)
                return;

            this._startedUtc = DateTime.UtcNow;
            this._isRunning = true;
            foreach (Task task in this._tasks.Values)
            {
                task.Execute();
            }
            this._isRunning = false;
        }

從任務列表中讀取任務並執行。

以上是簡單的分析,目前只是拿來主義,在學習和整理的同時加深一下對開源代碼的理解。

獨立博客地址:http://www.jqpress.com/post/190.aspx


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM