zoukankan      html  css  js  c++  java
  • 自动执行任务管理---TaskManage

     这篇主要配合数据使用

     先说数据库

     

    名字都很标准----------------------------------

    ------------------------------------------------------------------

    贴代码

    1.IScheduleTaskService-----------Task表的接口

        /// <summary>
        /// Task service interface
        /// </summary>
        public partial interface IScheduleTaskService
        {
            /// <summary>
            /// Deletes a task
            /// </summary>
            /// <param name="task">Task</param>
            void DeleteTask(ScheduleTask task);
    
            /// <summary>
            /// Gets a task
            /// </summary>
            /// <param name="taskId">Task identifier</param>
            /// <returns>Task</returns>
            ScheduleTask GetTaskById(int taskId);
    
            /// <summary>
            /// Gets a task by its type
            /// </summary>
            /// <param name="type">Task type</param>
            /// <returns>Task</returns>
            ScheduleTask GetTaskByType(string type);
    
            /// <summary>
            /// Gets all tasks
            /// </summary>
            /// <param name="showHidden">A value indicating whether to show hidden records</param>
            /// <returns>Tasks</returns>
            IList<ScheduleTask> GetAllTasks(bool showHidden = false);
    
            /// <summary>
            /// Inserts a task
            /// </summary>
            /// <param name="task">Task</param>
            void InsertTask(ScheduleTask task);
    
            /// <summary>
            /// Updates the task
            /// </summary>
            /// <param name="task">Task</param>
            void UpdateTask(ScheduleTask task);
        }
    View Code

    2.ScheduleTaskService-------------Task表的实现

        /// <summary>
        /// Task service
        /// </summary>
        public partial class ScheduleTaskService : IScheduleTaskService
        {
            #region Fields
    
            private readonly IRepository<ScheduleTask> _taskRepository;
    
            #endregion
    
            #region Ctor
    
            public ScheduleTaskService(IRepository<ScheduleTask> taskRepository)
            {
                this._taskRepository = taskRepository;
            }
    
            #endregion
    
            #region Methods
    
            /// <summary>
            /// Deletes a task
            /// </summary>
            /// <param name="task">Task</param>
            public virtual void DeleteTask(ScheduleTask task)
            {
                if (task == null)
                    throw new ArgumentNullException("task");
    
                _taskRepository.Delete(task);
            }
    
            /// <summary>
            /// Gets a task
            /// </summary>
            /// <param name="taskId">Task identifier</param>
            /// <returns>Task</returns>
            public virtual ScheduleTask GetTaskById(int taskId)
            {
                if (taskId == 0)
                    return null;
    
                return _taskRepository.GetById(taskId);
            }
    
            /// <summary>
            /// Gets a task by its type
            /// </summary>
            /// <param name="type">Task type</param>
            /// <returns>Task</returns>
            public virtual ScheduleTask GetTaskByType(string type)
            {
                if (String.IsNullOrWhiteSpace(type))
                    return null;
    
                var query = _taskRepository.Table;
                query = query.Where(st => st.Type == type);
                query = query.OrderByDescending(t => t.Id);
    
                var task = query.FirstOrDefault();
                return task;
            }
    
            /// <summary>
            /// Gets all tasks
            /// </summary>
            /// <param name="showHidden">A value indicating whether to show hidden records</param>
            /// <returns>Tasks</returns>
            public virtual IList<ScheduleTask> GetAllTasks(bool showHidden = false)
            {
                var query = _taskRepository.Table;
                if (!showHidden)
                {
                    query = query.Where(t => t.Enabled);
                }
                query = query.OrderByDescending(t => t.Seconds);
    
                var tasks = query.ToList();
                return tasks;
            }
    
            /// <summary>
            /// Inserts a task
            /// </summary>
            /// <param name="task">Task</param>
            public virtual void InsertTask(ScheduleTask task)
            {
                if (task == null)
                    throw new ArgumentNullException("task");
    
                _taskRepository.Insert(task);
            }
    
            /// <summary>
            /// Updates the task
            /// </summary>
            /// <param name="task">Task</param>
            public virtual void UpdateTask(ScheduleTask task)
            {
                if (task == null)
                    throw new ArgumentNullException("task");
    
                _taskRepository.Update(task);
            }
    
            #endregion
        }
    View Code

    IRepository--------后续写数据库相关的时候再连着EF一起说------------------------

    3.ScheduleTask---------------------实体类

        /// <summary>
        /// Schedule task
        /// </summary>
        public partial class ScheduleTask : BaseEntity
        {
            /// <summary>
            /// Gets or sets the name
            /// </summary>
            public string Name { get; set; }
    
            /// <summary>
            /// Gets or sets the run period (in seconds)
            /// </summary>
            public int Seconds { get; set; }
    
            /// <summary>
            /// Gets or sets the type of appropriate ITask class
            /// </summary>
            public string Type { get; set; }
    
            /// <summary>
            /// Gets or sets the value indicating whether a task is enabled
            /// </summary>
            public bool Enabled { get; set; }
    
            /// <summary>
            /// Gets or sets the value indicating whether a task should be stopped on some error
            /// </summary>
            public bool StopOnError { get; set; }
    
    
            /// <summary>
            /// Gets or sets the machine name (instance) that leased this task. It's used when running in web farm (ensure that a task in run only on one machine). It could be null when not running in web farm.
            /// </summary>
            public string LeasedByMachineName { get; set; }
            /// <summary>
            /// Gets or sets the datetime until the task is leased by some machine (instance). It's used when running in web farm (ensure that a task in run only on one machine).
            /// </summary>
            public DateTime? LeasedUntilUtc { get; set; }
    
            /// <summary>
            /// Gets or sets the datetime when it was started last time
            /// </summary>
            public DateTime? LastStartUtc { get; set; }
            /// <summary>
            /// Gets or sets the datetime when it was finished last time (no matter failed ir success)
            /// </summary>
            public DateTime? LastEndUtc { get; set; }
            /// <summary>
            /// Gets or sets the datetime when it was sucessfully finished last time
            /// </summary>
            public DateTime? LastSuccessUtc { get; set; }
        }
    View Code

    4.BaseEntity------------------------实体类,基类,写的很有意思

        /// <summary>
        /// Base class for entities
        /// </summary>
        public abstract partial class BaseEntity
        {
            /// <summary>
            /// Gets or sets the entity identifier
            /// </summary>
            public int Id { get; set; }
    
            public override bool Equals(object obj)
            {
                return Equals(obj as BaseEntity);
            }
    
            private static bool IsTransient(BaseEntity obj)
            {
                return obj != null && Equals(obj.Id, default(int));
            }
    
            private Type GetUnproxiedType()
            {
                return GetType();
            }
    
            public virtual bool Equals(BaseEntity other)
            {
                if (other == null)
                    return false;
    
                if (ReferenceEquals(this, other))
                    return true;
    
                if (!IsTransient(this) &&
                    !IsTransient(other) &&
                    Equals(Id, other.Id))
                {
                    var otherType = other.GetUnproxiedType();
                    var thisType = GetUnproxiedType();
                    return thisType.IsAssignableFrom(otherType) ||
                            otherType.IsAssignableFrom(thisType);
                }
    
                return false;
            }
    
            public override int GetHashCode()
            {
                if (Equals(Id, default(int)))
                    return base.GetHashCode();
                return Id.GetHashCode();
            }
    
            public static bool operator ==(BaseEntity x, BaseEntity y)
            {
                return Equals(x, y);
            }
    
            public static bool operator !=(BaseEntity x, BaseEntity y)
            {
                return !(x == y);
            }
        }
    View Code

    5.Mapping映射

        public partial class ScheduleTaskMap : EntityTypeConfiguration<ScheduleTask>
        {
            public ScheduleTaskMap()
            {
                this.ToTable("ScheduleTask");
                this.HasKey(t => t.Id);
                this.Property(t => t.Name).IsRequired();
                this.Property(t => t.Type).IsRequired();
            }
        }
    View Code

    -----------------至此操作上面scheduletask表的方法实体类都写完了-----------------------------------

    6.ITask-----自动任务执行继承这个接口就可以了

        /// <summary>
        /// Interface that should be implemented by each task
        /// </summary>
        public partial interface ITask
        {
            /// <summary>
            /// Executes a task
            /// </summary>
            void Execute();
        }
    View Code

    7.Task

        /// <summary>
        /// Task
        /// </summary>
        public partial class Task
        {
            #region Ctor
    
            /// <summary>
            /// Ctor for Task
            /// </summary>
            private Task()
            {
                this.Enabled = true;
            }
    
            /// <summary>
            /// Ctor for Task
            /// </summary>
            /// <param name="task">Task </param>
            public Task(ScheduleTask task)
            {
                this.Type = task.Type;
                this.Enabled = task.Enabled;
                this.StopOnError = task.StopOnError;
                this.Name = task.Name;
            }
    
            #endregion
    
            #region Utilities
    
            private ITask CreateTask(ILifetimeScope scope)
            {
                ITask task = null;
                if (this.Enabled)
                {
                    var type2 = System.Type.GetType(this.Type);
                    if (type2 != null)
                    {
                        object instance;
                        if (!EngineContext.Current.ContainerManager.TryResolve(type2, scope, out instance))
                        {
                            //not resolved
                            instance = EngineContext.Current.ContainerManager.ResolveUnregistered(type2, scope);
                        }
                        task = instance as ITask;
                    }
                }
                return task;
            }
    
            #endregion
    
            #region Methods
    
            /// <summary>
            /// Executes the task
            /// </summary>
            /// <param name="throwException">A value indicating whether exception should be thrown if some error happens</param>
            /// <param name="dispose">A value indicating whether all instances should be disposed after task run</param>
            /// <param name="ensureRunOnOneWebFarmInstance">A value indicating whether we should ensure this task is run on one farm node at a time</param>
            public void Execute(bool throwException = false, bool dispose = true, bool ensureRunOnOneWebFarmInstance = true)
            {
                //background tasks has an issue with Autofac
                //because scope is generated each time it's requested
                //that's why we get one single scope here
                //this way we can also dispose resources once a task is completed
                var scope = EngineContext.Current.ContainerManager.Scope();
                var scheduleTaskService = EngineContext.Current.ContainerManager.Resolve<IScheduleTaskService>("", scope);
                var scheduleTask = scheduleTaskService.GetTaskByType(this.Type);
    
                try
                {
                    //task is run on one farm node at a time?
                    if (ensureRunOnOneWebFarmInstance)
                    {
                        //is web farm enabled (multiple instances)?
                        var nopConfig = EngineContext.Current.ContainerManager.Resolve<NopConfig>("", scope);
                        if (nopConfig.MultipleInstancesEnabled)
                        {
                            var machineNameProvider = EngineContext.Current.ContainerManager.Resolve<IMachineNameProvider>("", scope);
                            var machineName = machineNameProvider.GetMachineName();
                            if (String.IsNullOrEmpty(machineName))
                            {
                                throw new Exception("Machine name cannot be detected. You cannot run in web farm.");
                                //actually in this case we can generate some unique string (e.g. Guid) and store it in some "static" (!!!) variable
                                //then it can be used as a machine name
                            }
    
                            //lease can't be aquired only if for a different machine and it has not expired
                            if (scheduleTask.LeasedUntilUtc.HasValue &&
                                scheduleTask.LeasedUntilUtc.Value >= DateTime.UtcNow &&
                                scheduleTask.LeasedByMachineName != machineName)
                                return;
    
                            //lease the task. so it's run on one farm node at a time
                            scheduleTask.LeasedByMachineName = machineName;
                            scheduleTask.LeasedUntilUtc = DateTime.UtcNow.AddMinutes(30);
                            scheduleTaskService.UpdateTask(scheduleTask);
                        }
                    }
    
                    //initialize and execute
                    var task = this.CreateTask(scope);
                    if (task != null)
                    {
                        this.LastStartUtc = DateTime.UtcNow;
                        if (scheduleTask != null)
                        {
                            //update appropriate datetime properties
                            scheduleTask.LastStartUtc = this.LastStartUtc;
                            scheduleTaskService.UpdateTask(scheduleTask);
                        }
                        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.ContainerManager.Resolve<ILogger>("", scope);
                    logger.Error(string.Format("Error while running the '{0}' schedule task. {1}", this.Name, exc.Message), exc);
                    if (throwException)
                        throw;
                }
    
                if (scheduleTask != null)
                {
                    //update appropriate datetime properties
                    scheduleTask.LastEndUtc = this.LastEndUtc;
                    scheduleTask.LastSuccessUtc = this.LastSuccessUtc;
                    scheduleTaskService.UpdateTask(scheduleTask);
                }
    
                //dispose all resources
                if (dispose)
                {
                    scope.Dispose();
                }
            }
    
            #endregion
    
            #region Properties
    
            /// <summary>
            /// Datetime of the last start
            /// </summary>
            public DateTime? LastStartUtc { get; private set; }
    
            /// <summary>
            /// Datetime of the last end
            /// </summary>
            public DateTime? LastEndUtc { get; private set; }
    
            /// <summary>
            /// Datetime of the last success
            /// </summary>
            public DateTime? LastSuccessUtc { get; private set; }
    
            /// <summary>
            /// A value indicating type of the task
            /// </summary>
            public string Type { get; private set; }
    
            /// <summary>
            /// A value indicating whether to stop task on error
            /// </summary>
            public bool StopOnError { get; private set; }
    
            /// <summary>
            /// Get the task name
            /// </summary>
            public string Name { get; private set; }
    
            /// <summary>
            /// A value indicating whether the task is enabled
            /// </summary>
            public bool Enabled { get; set; }
    
            #endregion
        }
    View Code

    8.TaskManager

        /// <summary>
        /// Represents task manager
        /// </summary>
        public partial class TaskManager
        {
            private static readonly TaskManager _taskManager = new TaskManager();
            private readonly List<TaskThread> _taskThreads = new List<TaskThread>();
            private const int _notRunTasksInterval = 60 * 30; //30 minutes
    
            private TaskManager()
            {
            }
    
            /// <summary>
            /// Initializes the task manager
            /// </summary>
            public void Initialize()
            {
                this._taskThreads.Clear();
    
                var taskService = EngineContext.Current.Resolve<IScheduleTaskService>();
                var scheduleTasks = taskService
                    .GetAllTasks()
                    .OrderBy(x => x.Seconds)
                    .ToList();
    
                //group by threads with the same seconds
                foreach (var scheduleTaskGrouped in scheduleTasks.GroupBy(x => x.Seconds))
                {
                    //create a thread
                    var taskThread = new TaskThread
                    {
                        Seconds = scheduleTaskGrouped.Key
                    };
                    foreach (var scheduleTask in scheduleTaskGrouped)
                    {
                        var task = new Task(scheduleTask);
                        taskThread.AddTask(task);
                    }
                    this._taskThreads.Add(taskThread);
                }
    
                //sometimes a task period could be set to several hours (or even days).
                //in this case a probability that it'll be run is quite small (an application could be restarted)
                //we should manually run the tasks which weren't run for a long time
                var notRunTasks = scheduleTasks
                    //find tasks with "run period" more than 30 minutes
                    .Where(x => x.Seconds >= _notRunTasksInterval)
                    .Where(x => !x.LastStartUtc.HasValue || x.LastStartUtc.Value.AddSeconds(x.Seconds) < DateTime.UtcNow)
                    .ToList();
                //create a thread for the tasks which weren't run for a long time
                if (notRunTasks.Any())
                {
                    var taskThread = new TaskThread
                    {
                        RunOnlyOnce = true,
                        Seconds = 60 * 5 //let's run such tasks in 5 minutes after application start
                    };
                    foreach (var scheduleTask in notRunTasks)
                    {
                        var task = new Task(scheduleTask);
                        taskThread.AddTask(task);
                    }
                    this._taskThreads.Add(taskThread);
                }
            }
    
            /// <summary>
            /// Starts the task manager
            /// </summary>
            public void Start()
            {
                foreach (var taskThread in this._taskThreads)
                {
                    taskThread.InitTimer();
                }
            }
    
            /// <summary>
            /// Stops the task manager
            /// </summary>
            public void Stop()
            {
                foreach (var taskThread in this._taskThreads)
                {
                    taskThread.Dispose();
                }
            }
    
            /// <summary>
            /// Gets the task mamanger instance
            /// </summary>
            public static TaskManager Instance
            {
                get
                {
                    return _taskManager;
                }
            }
    
            /// <summary>
            /// Gets a list of task threads of this task manager
            /// </summary>
            public IList<TaskThread> TaskThreads
            {
                get
                {
                    return new ReadOnlyCollection<TaskThread>(this._taskThreads);
                }
            }
        }
    View Code

    9.TaskThread

        /// <summary>
        /// Represents task thread
        /// </summary>
        public partial class TaskThread : IDisposable
        {
            private Timer _timer;
            private bool _disposed;
            private readonly Dictionary<string, Task> _tasks;
    
            internal TaskThread()
            {
                this._tasks = new Dictionary<string, Task>();
                this.Seconds = 10 * 60;
            }
    
            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;
            }
    
            private void TimerHandler(object state)
            {
                this._timer.Change(-1, -1);
                this.Run();
                if (this.RunOnlyOnce)
                {
                    this.Dispose();
                }
                else
                {
                    this._timer.Change(this.Interval, this.Interval);
                }
            }
    
            /// <summary>
            /// Disposes the instance
            /// </summary>
            public void Dispose()
            {
                if ((this._timer != null) && !this._disposed)
                {
                    lock (this)
                    {
                        this._timer.Dispose();
                        this._timer = null;
                        this._disposed = true;
                    }
                }
            }
    
            /// <summary>
            /// Inits a timer
            /// </summary>
            public void InitTimer()
            {
                if (this._timer == null)
                {
                    this._timer = new Timer(new TimerCallback(this.TimerHandler), null, this.Interval, this.Interval);
                }
            }
    
            /// <summary>
            /// Adds a task to the thread
            /// </summary>
            /// <param name="task">The task to be added</param>
            public void AddTask(Task task)
            {
                if (!this._tasks.ContainsKey(task.Name))
                {
                    this._tasks.Add(task.Name, task);
                }
            }
    
    
            /// <summary>
            /// Gets or sets the interval in seconds at which to run the tasks
            /// </summary>
            public int Seconds { get; set; }
    
            /// <summary>
            /// Get or sets a datetime when thread has been started
            /// </summary>
            public DateTime StartedUtc { get; private set; }
    
            /// <summary>
            /// Get or sets a value indicating whether thread is running
            /// </summary>
            public bool IsRunning { get; private set; }
    
            /// <summary>
            /// Get a list of tasks
            /// </summary>
            public IList<Task> Tasks
            {
                get
                {
                    var list = new List<Task>();
                    foreach (var task in this._tasks.Values)
                    {
                        list.Add(task);
                    }
                    return new ReadOnlyCollection<Task>(list);
                }
            }
    
            /// <summary>
            /// Gets the interval at which to run the tasks
            /// </summary>
            public int Interval
            {
                get
                {
                    return this.Seconds * 1000;
                }
            }
    
            /// <summary>
            /// Gets or sets a value indicating whether the thread whould be run only once (per appliction start)
            /// </summary>
            public bool RunOnlyOnce { get; set; }
        }
    View Code

    -------------------------

    10.Global.ascx.cs

            protected void Application_Start()
            {           
                 TaskManager.Instance.Initialize();
                 TaskManager.Instance.Start();        
            }        
    View Code

    使用

    CancelOrderTask-----------路径:BotanicSystem.Services.Order.CancelOrderTask,BotanicSystem.Services

    贴一条数据库数据

    3 订单自动取消 1000 BotanicSystem.Services.Order.CancelOrderTask,BotanicSystem.Services False False NULL NULL 2016-10-13 00:54:31.927 NULL NULL

    贴代码

        public partial class CancelOrderTask:ITask
        {
            #region fields
    
            private readonly IOrderInfoService _orderInfoService;
            #endregion
    
    
            #region Ctor
    
            public CancelOrderTask(IOrderInfoService orderInfoService)
            {
                _orderInfoService = orderInfoService;
            }
    
            #endregion
            public void Execute()
            {
                //获取所有30分钟内未支付的订单
                var cancelOrders = _orderInfoService.GetListByWhere(
                                    p =>
                                        DbFunctions.DiffMinutes(p.Add_Time, DateTime.Now) >= 30 &&
                                        (p.Status == (int) OrderStatus.未提交) || p.Status == (int) OrderStatus.进行中);
    
                //设置订单状态为取消
                foreach (var order in cancelOrders)
                {
                    order.Status = (int) OrderStatus.已过期;
                }
                _orderInfoService.UpdateOrders(cancelOrders);
            }
        }
    View Code
  • 相关阅读:
    如何完成域名和ip地址的绑定
    如何把域名解析到网站空间IP上?
    网站和数据库分开放,可以实现吗
    访问网站出现 Directory Listing Denied This Virtual Directory
    访问网站出现 Directory Listing Denied This Virtual Directory
    免费空间上的mysql数据库怎么连接?
    我不是你的菜
    很奇怪木瓜移动一上就火了
    敏捷产业
    前端开发工具
  • 原文地址:https://www.cnblogs.com/sunzgod/p/6233832.html
Copyright © 2011-2022 走看看