Ejemplo n.º 1
0
 private IAstNode <Target> ParseSingleSlashNodeUnderTarget()
 {
     return(_scanner.Token switch
     {
         TaskToken _ => ParseTaskNode() as IAstNode <Target>,
         _ => ParseLogNodeWithType(LogNodeType.Direct),
     });
Ejemplo n.º 2
0
 public TaskTokenViewModel(TaskToken model)
 {
     _model = model;
 }
Ejemplo n.º 3
0
        private void Fire(DateTime timestamp, IEnumerable <ScheduleToken> schedules)
        {
            if (schedules == null)
            {
                return;
            }

            //首先获取待处理的任务凭证
            var pendding = _token;

            //如果待处理的任务凭证有效并且指定要重新触发的时间大于或等于待触发时间则忽略当次调度
            if (pendding != null && timestamp >= pendding.Timestamp)
            {
                return;
            }

            //创建一个新的任务凭证
            var current = new TaskToken(timestamp, schedules);

            //循环确保本次替换的任务凭证没有覆盖到其他线程乱入的
            while (pendding == null || timestamp < pendding.Timestamp)
            {
                //将新的触发凭证设置到全局变量,并确保该设置不会覆盖其他线程的乱入
                var last = Interlocked.CompareExchange(ref _token, current, pendding);

                //如果设置成功则退出该循环
                if (last == pendding)
                {
                    break;
                }
                else                 //设置失败:表示中间有其他线程的乱入,则将乱入的最新值设置为比对的凭证
                {
                    pendding = last;
                }
            }

            //注意:再次确认待处理的任务凭证有效并且指定要重新触发的时间大于或等于待触发时间则忽略当次调度
            if (pendding != null && timestamp >= pendding.Timestamp)
            {
                //将刚创建的任务标记销毁
                current.Dispose();

                //退出
                return;
            }

            //如果原有任务凭证不为空,则将原有任务取消掉
            if (pendding != null)
            {
                pendding.Cancel();
            }

            //获取延迟的时长
            var duration = Utility.GetDuration(timestamp);

            Task.Delay(duration).ContinueWith((task, state) =>
            {
                //获取当前的任务调度凭证
                var token = (TaskToken)state;

                //注意:防坑处理!!!
                //任务线程可能没有延迟足够的时长就提前进入,所以必须防止这种提前进入导致的触发器的触发时间计算错误
                if (Utility.Now() < token.Timestamp)
                {
                    SpinWait.SpinUntil(() => token.IsCancellationRequested || DateTime.Now.Ticks >= token.Timestamp.Ticks);
                }

                //如果任务已经被取消,则退出
                if (token.IsCancellationRequested)
                {
                    return;
                }

                //将最近触发时间点设为此时此刻
                _lastTime = token.Timestamp;

                //注意:必须将待处理任务标记置空(否则会误导Scan方法重新进入Fire方法内的有效性判断)
                _token = null;

                //启动新一轮的调度扫描
                this.Scan();

                //设置处理次数
                int count = 0;

                //激发“Occurring”事件
                this.OnOccurring(token.Identity);

                //遍历待执行的调度项集合(该集合内部确保了线程安全)
                foreach (var schedule in token.Schedules)
                {
                    //遍历当前调度项内的所有处理器集合(该集合内部确保了线程安全)
                    foreach (var handler in schedule.Handlers)
                    {
                        //创建处理上下文对象
                        var context = new HandlerContext(this, schedule.Trigger, token.Identity, token.Timestamp, count++);

                        Task.Run(() => this.Handle(handler, context))                        //异步调用处理器进行处理(该方法内会屏蔽异常,并对执行异常的处理器进行重发处理)
                        .ContinueWith(t => this.OnHandled(handler, context, t.Result));      //异步调用处理器完成后,再激发“Handled”事件
                    }
                }

                //激发“Occurred”事件
                this.OnOccurred(token.Identity, count);
            }, current, current.GetToken());

            try
            {
                //激发“Scheduled”事件
                this.OnScheduled(current.Identity, schedules.Sum(p => p.Count), schedules.Select(p => p.Trigger).ToArray());
            }
            catch (Exception ex)
            {
                Zongsoft.Diagnostics.Logger.Error(ex);
            }
        }