Exemplo n.º 1
0
        public static bool AddJob(JobArgs args, bool fromRedis = false)
        {
            ArgumentHelper.AssertValuesPositive(args.TenantId);
            ArgumentHelper.AssertNotNullOrEmpty(args.JobKey);
            ArgumentHelper.AssertNotNullOrEmpty(args.JobAppName);
            ArgumentHelper.AssertNotNull(args.Job, "job must not null");

            string redisKey     = MakeRedisKey(args.TenantId, args.JobAppName);
            string redisLockKey = MakeLockKey(args.TenantId, args.JobKey, args.JobAppName);

            //不是从redis加载的需要保存到redis,如果是从redis加载则不用再回写了
            if (!fromRedis)
            {
                string redisJobValue = MakeJobValue(args.OperatorId, args.RunTime, args.Job);
                RedisCacheHelper.SetHRedis(args.TenantId, redisKey, args.JobKey, redisJobValue);
            }

            JobManager.AddJob(
                () =>
            {
                //加分布式锁
                //获取Key 对应的Value。
                //拆Value,获取Runtime
                //比较runtime,如果在允许的时间差范围内,则执行。否则,return
                //执行完,删掉jobKey
                //释放分布式锁
                ApplicationContext.Current.TenantId        = args.TenantId;
                ApplicationContext.Current.UserId          = args.OperatorId;
                ApplicationContext.Current.ApplicationName = args.JobAppName;
                var lockRes = DistributeRedisLock.TryLock(args.TenantId, redisLockKey, "", args.LimitSeconds);
                if (!lockRes)
                {
                    LogHelper.Instance.Debug($"定时任务未执行,加锁失败。LockKey:{redisLockKey},JobKey:{args.JobKey}");
                    return;
                }
                try
                {
                    var jobValue = RedisCacheHelper.GetHRedis(args.TenantId, redisKey, args.JobKey);
                    if (string.IsNullOrEmpty(jobValue))
                    {
                        LogHelper.Instance.Debug($"定时任务未执行,Key不存在。{args.JobKey}");
                        return;
                    }
                    var jobInfo = GetJobValue(jobValue);
                    if (jobInfo == null)
                    {
                        LogHelper.Instance.Debug($"定时任务未执行,JobInfo为空。JobKey:{args.JobKey}, JobValue:{jobValue}");
                        return;
                    }
                    //比如,一个Job的实际执行时间是12:00:00,Redis里存的是12:00:00,实际FluentScheduler也是12:00:00触发执行的。
                    //但是执行到比较时间这块,可能是12:00:05了(可能要排队、或者性能问题等),导致时间不匹配。因此,我们允许时间出现轻微误差
                    //但是,如果时间间隔超过该轻微误差(1分钟),则认为时间不匹配
                    if (Math.Abs((jobInfo.Item2 - DateTime.Now).TotalSeconds) >= 60)
                    {
                        LogHelper.Instance.Debug($"定时任务未执行,时间不匹配。JobKey:{args.JobKey}, JobValue:{jobValue}");
                        return;
                    }
                    args.Job.Execute();
                    RedisCacheHelper.DelHRedis(args.TenantId, redisKey, args.JobKey);
                    LogHelper.Instance.Debug($"执行定时任务成功。JobKey:{args.JobKey},JobValue{jobValue}");
                }
                catch (Exception ex)
                {
                    LogHelper.Instance.Error($"执行定时任务异常。JobKey:{args.JobKey},EX:{ex.Message}");
                }
                finally
                {
                    DistributeRedisLock.UnLock(args.TenantId, redisLockKey, "");
                }
            },
                (schedule) =>
            {
                RememberTenant(args.TenantId);
                schedule.WithName(args.JobKey).ToRunOnceAt(args.RunTime);
            });
            return(true);
        }