Exemplo n.º 1
0
        public ITask[] Acquire(AcquireModel model)
        {
            var job = model.Job?.Trim();

            if (job.IsNullOrEmpty())
            {
                return(new TaskModel[0]);
            }

            var app = _App;

            if (app == null)
            {
                return(new TaskModel[0]);
            }

            // 应用停止发放作业
            app = App.FindByID(app.ID) ?? app;
            if (!app.Enable)
            {
                return(new TaskModel[0]);
            }
            var jb = app.Jobs.FirstOrDefault(e => e.Name == job);

            // 全局锁,确保单个作业只有一个线程在分配作业
            using var ck = Cache.AcquireLock($"Job:{jb.ID}", 15_000);

            // 找到作业。为了确保能够快速拿到新的作业参数,这里做二次查询
            if (jb != null)
            {
                jb = Job.Find(Job._.ID == jb.ID);
            }
            else
            {
                jb = Job.FindByAppIDAndName(app.ID, job);
            }

            if (jb == null)
            {
                throw new XException($"应用[{app.ID}/{app.Name}]下未找到作业[{job}]");
            }
            if (jb.Step == 0 || jb.Start.Year <= 2000)
            {
                throw new XException("作业[{0}/{1}]未设置开始时间或步进", jb.ID, jb.Name);
            }

            var online = GetOnline(app, _Net);

            var list = new List <JobTask>();

            // 每分钟检查一下错误任务和中断任务
            CheckErrorTask(app, jb, model.Count, list);

            // 错误项不够时,增加切片
            if (list.Count < model.Count)
            {
                //var ps = ControllerContext.Current.Parameters;
                var server = online.Name;
                var pid    = online.ProcessId;
                //var topic = ps["topic"] + "";
                var ip = _Net.Remote.Host;

                switch (jb.Mode)
                {
                case JobModes.Message:
                    list.AddRange(jb.AcquireMessage(model.Topic, server, ip, pid, model.Count - list.Count, Cache));
                    break;

                case JobModes.Data:
                case JobModes.Alarm:
                //case JobModes.CSharp:
                //case JobModes.Sql:
                default:
                {
                    // 如果能够切片,则查询数据库后进入,避免缓存导致重复
                    if (jb.TrySplit(jb.Start, jb.Step, out var end))
                    {
                        // 申请任务前,不能再查数据库,那样子会导致多线程脏读,从而出现多客户端分到相同任务的情况
                        //jb = Job.FindByKey(jb.ID);
                        list.AddRange(jb.Acquire(server, ip, pid, model.Count - list.Count, Cache));
                    }
                }
                break;
                }
            }

            // 记录状态
            online.Tasks += list.Count;
            online.SaveAsync();

            return(list.Select(e => e.ToModel()).ToArray());
        }