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()); }