C# 简单的 Job 作业~

改变之前的前言,这次咱这样写:

一个习惯只需十天的坚持就可以养成,坏习惯也不例外!吸烟喝酒的我能否做到十天不吸烟喝酒呢?

呵呵

养成习惯关键还要看决心和意志力

恩,努力控烟吧!

废话说完了,就进入咱们的小程序:Job作业。

我这里所说的Job作业并没有 Quartz 或者 Quartz.Net 那么高大尚,今天和大家介绍的作业是一个非常非常轻量级的框架,与其说框架倒不如说是一个只有不足千行的代码!

哈哈

如下:

按照我的步骤,一起来构建一个 Job 作业调度的小项目,

步骤一:新建一个解决方案,姑且命名为Job吧,如下:

此解决方案有两个项目,一个是Job控制台项目,一个是CronJob类库,

步骤二:复制粘贴下边的代码

控制台 Program.cs 代码如下

using CronJob;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Job
{
    class Program
    {
        private static readonly CronMon CronMon = new CronMon();
        static void Main(string[] args)
        {
            Start();
            while (true)
            {
                Console.WriteLine(string.Format("{0}: Running", DateTime.Now.ToString("s")));
                Thread.Sleep(60 * 1000);
            }
        }

        public static void Start()
        {
            Init();
            CronMon.Start();
        }
        //Cron 表达式范例
        //TODO 移到配置文件里
        //* * * * * = Minutes Hours Day-of-Month Month Day-of-Week
        //每隔1分钟执行一次:*/1 * * *
        //每天23点执行一次:0 23 * *
        //每天凌晨1点执行一次:0 1 * *
        //每月1号凌晨1点执行一次:0 1 1 *
        //在26分、29分、33分执行一次:26,29,33 * * *
        //每天的0点、13点、18点、21点都执行一次: 0 0,13,18,21 * *
        private static void Init()
        {
            CronMon.AddJob(new JobFoobar("*/1 * * *"));
            CronMon.AddJob(new JobFoobar2("*/1 * * *"));
        }

        public static void Abort()
        {
            CronMon.Stop();
        }
    }
}
View Code

CronJob类库代码如下:

CronJob类库中有两个文件夹,一个是基类文件夹(Base),一个是你的作业文件夹(Jobs):

关于基类文件夹没什么可说的,关于作业文件夹是指你的项目中需要做调度的任务都可以写成Job放在这个文件夹中,

基类代码如下:

CronJobBase.cs

using System;
using System.Threading;

namespace CronJob
{
    public interface ICronJob
    {
        void Run(DateTime dateTime);
        void Abort();
    }
    public class CronJobBase : ICronJob
    {
        private readonly object _lock = new object();
        private readonly CronSchedule _cronSchedule;
        private Thread _thread;
        public CronJobBase(string schedule)
        {
            _cronSchedule = new CronSchedule(schedule);
        }
        public void Run(DateTime dateTime)
        {
            lock (_lock)
            {
                if (!_cronSchedule.IsTime(dateTime))
                    return;

                if (_thread!= null && _thread.ThreadState == ThreadState.Running)
                    return;
                _thread = new Thread(ExecuteHandler);
                _thread.Start();
            }
        }

        public void Abort()
        {
            _thread.Abort();
        }

        private void ExecuteHandler()
        {
            try
            {
                Execute();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error:", ex);
            }
        }

        protected virtual void Execute()
        {

        }
    }
}
View Code

CronMon.cs

using System;
using System.Collections.Generic;
using System.Timers;
using System.Threading;

namespace CronJob
{
    public interface ICronMon
    {
        void AddJob(ICronJob job);
        void Start();
        void Stop();
    }

    public class CronMon : ICronMon
    {
        private readonly System.Timers.Timer _timer = new System.Timers.Timer(30000);
        private readonly List<ICronJob> _cronJobs = new List<ICronJob>();
        private DateTime _last = DateTime.Now;

        public CronMon()
        {
            _timer.AutoReset = true;
            _timer.Elapsed += timer_elapsed;
        }

        public void AddJob(ICronJob job)
        {
            _cronJobs.Add(job);
        }

        public void Start()
        {
            _timer.Start();
        }

        public void Stop()
        {
            _timer.Stop();

            foreach (var cronJob in _cronJobs)
            {
                var job = (CronJobBase) cronJob;
                job.Abort();
            }
        }

        private void timer_elapsed(object sender, ElapsedEventArgs e)
        {
            if (DateTime.Now.Minute != _last.Minute)
            {
                _last = DateTime.Now;
                foreach (ICronJob job in _cronJobs)
                    job.Run(DateTime.Now);
            }
        }
    }
}
View Code

CronSchedule.cs

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace CronJob
{
    public interface ICronSchedule
    {
        bool IsValid(string expression);
        bool IsTime(DateTime dateTime);
    }

    public class CronSchedule : ICronSchedule
    {
        private static readonly Regex DividedRegex = new Regex(@"(\*/\d+)");
        private static readonly Regex RangeRegex = new Regex(@"(\d+\-\d+)\/?(\d+)?");
        private static readonly Regex WildRegex = new Regex(@"(\*)");
        private static readonly Regex ListRegex = new Regex(@"(((\d+,)*\d+)+)");
        private static readonly Regex ValidationRegex = new Regex(DividedRegex + "|" + RangeRegex + "|" + WildRegex + "|" + ListRegex);
        private readonly string _expression;

        public List<int> Minutes;
        public List<int> Hours;
        public List<int> DaysOfMonth;
        public List<int> Months;
        public List<int> DaysOfWeek;
        public CronSchedule()
        {
        }

        public CronSchedule(string expressions)
        {
            _expression = expressions;
            Generate();
        }

        private bool isValid()
        {
            return IsValid(_expression);
        }

        public bool IsValid(string expression)
        {
            MatchCollection matches = ValidationRegex.Matches(expression);
            return matches.Count > 0;//== 5;
        }

        public bool IsTime(DateTime dateTime)
        {
            return Minutes.Contains(dateTime.Minute) &&
                   Hours.Contains(dateTime.Hour) &&
                   DaysOfMonth.Contains(dateTime.Day) &&
                   Months.Contains(dateTime.Month) &&
                   DaysOfWeek.Contains((int)dateTime.DayOfWeek);
        }

        private void Generate()
        {
            if (!isValid()) return;

            MatchCollection matches = ValidationRegex.Matches(_expression);

            GenerateMinutes(matches[0].ToString());

            if (matches.Count > 1)
                GenerateHours(matches[1].ToString());
            else
                GenerateHours("*");

            if (matches.Count > 2)
                GenerateDaysOfMonth(matches[2].ToString());
            else
                GenerateDaysOfMonth("*");

            if (matches.Count > 3)
                GenerateMonths(matches[3].ToString());
            else
                GenerateMonths("*");

            if (matches.Count > 4)
                GenerateDaysOfWeeks(matches[4].ToString());
            else
                GenerateDaysOfWeeks("*");
        }

        private void GenerateMinutes(string match)
        {
            Minutes = GenerateValues(match, 0, 60);
        }

        private void GenerateHours(string match)
        {
            Hours = GenerateValues(match, 0, 24);
        }

        private void GenerateDaysOfMonth(string match)
        {
            DaysOfMonth = GenerateValues(match, 1, 32);
        }

        private void GenerateMonths(string match)
        {
            Months = GenerateValues(match, 1, 13);
        }

        private void GenerateDaysOfWeeks(string match)
        {
            DaysOfWeek = GenerateValues(match, 0, 7);
        }

        private List<int> GenerateValues(string configuration, int start, int max)
        {
            if (DividedRegex.IsMatch(configuration)) return DividedArray(configuration, start, max);
            if (RangeRegex.IsMatch(configuration)) return RangeArray(configuration);
            if (WildRegex.IsMatch(configuration)) return WildArray(configuration, start, max);
            if (ListRegex.IsMatch(configuration)) return ListArray(configuration);

            return new List<int>();
        }

        private List<int> DividedArray(string configuration, int start, int max)
        {
            if (!DividedRegex.IsMatch(configuration))
                return new List<int>();

            List<int> ret = new List<int>();
            string[] split = configuration.Split("/".ToCharArray());
            int divisor = int.Parse(split[1]);

            for (int i = start; i < max; ++i)
                if (i % divisor == 0)
                    ret.Add(i);

            return ret;
        }

        private List<int> RangeArray(string configuration)
        {
            if (!RangeRegex.IsMatch(configuration))
                return new List<int>();

            List<int> ret = new List<int>();
            string[] split = configuration.Split("-".ToCharArray());
            int start = int.Parse(split[0]);
            int end = 0;
            if (split[1].Contains("/"))
            {
                split = split[1].Split("/".ToCharArray());
                end = int.Parse(split[0]);
                int divisor = int.Parse(split[1]);

                for (int i = start; i < end; ++i)
                    if (i % divisor == 0)
                        ret.Add(i);
                return ret;
            }
            else
                end = int.Parse(split[1]);

            for (int i = start; i <= end; ++i)
                ret.Add(i);

            return ret;
        }

        private List<int> WildArray(string configuration, int start, int max)
        {
            if (!WildRegex.IsMatch(configuration))
                return new List<int>();

            List<int> ret = new List<int>();

            for (int i = start; i < max; ++i)
                ret.Add(i);

            return ret;
        }

        private List<int> ListArray(string configuration)
        {
            if (!ListRegex.IsMatch(configuration))
                return new List<int>();

            List<int> ret = new List<int>();

            string[] split = configuration.Split(",".ToCharArray());

            foreach (string s in split)
                ret.Add(int.Parse(s));

            return ret;
        }
    }
}
View Code

作业代码如下:

Job1.cs

using CronJob;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CronJob
{
    public class JobFoobar : CronJobBase
    {
        public JobFoobar(string schedule)
            : base(schedule)
        {
        }

        protected override void Execute()
        {
           Console.WriteLine("作业开始执行");
            //do your logic
           Console.WriteLine("我是一个简答的Job作业,编号为:1");
           //do your logic
           Console.WriteLine("执行结束");
           //throw new Exception("fake error");
        }
    }
}
View Code

Job2.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CronJob
{
    public class JobFoobar2 : CronJobBase
    {
        public JobFoobar2(string schedule)
            : base(schedule)
        {
        }

        protected override void Execute()
        {
            Console.WriteLine("作业开始执行");
            //do your logic
            Console.WriteLine("我是一个简答的Job作业,编号为:2");
            //do your logic
            Console.WriteLine("执行结束");
            //throw new Exception("fake error");
        }
    }
}
View Code

OK,项目打造完成后,记得控制台项目引用基类项目,那么运行后,如下:

在我们的作业中设置的是每一分钟执行一次,

两分钟的时间,执行了两次!

OK,源码地址为:https://download.csdn.net/download/wolongbb/10276057

@陈卧龙的博客

posted @ 2018-03-08 16:57  天才卧龙  阅读(4006)  评论(0编辑  收藏  举报