Exemple #1
0
        public override IFetchedJob FetchNextJob([NotNull] string[] queues, CancellationToken cancellationToken)
        {
            if (queues == null)
            {
                throw new ArgumentNullException(nameof(queues));
            }

            string jobId     = null;
            string queueName = null;

            do
            {
                cancellationToken.ThrowIfCancellationRequested();

                for (int i = 0; i < queues.Length; i++)
                {
                    queueName = queues[i];
                    var queueKey   = _storage.GetRedisKey($"queue:{queueName}");
                    var fetchedKey = _storage.GetRedisKey($"queue:{queueName}:dequeued");
                    jobId = Redis.ListRightPopLeftPush(queueKey, fetchedKey);
                    if (jobId != null)
                    {
                        break;
                    }
                }

                if (jobId == null)
                {
                    _subscription.WaitForJob(_fetchTimeout, cancellationToken);
                }
            }while (jobId == null);

            // The job was fetched by the server. To provide reliability,
            // we should ensure, that the job will be performed and acquired
            // resources will be disposed even if the server will crash
            // while executing one of the subsequent lines of code.

            // The job's processing is splitted into a couple of checkpoints.
            // Each checkpoint occurs after successful update of the
            // job information in the storage. And each checkpoint describes
            // the way to perform the job when the server was crashed after
            // reaching it.

            // Checkpoint #1-1. The job was fetched into the fetched list,
            // that is being inspected by the FetchedJobsWatcher instance.
            // Job's has the implicit 'Fetched' state.

            Redis.HashSet(
                _storage.GetRedisKey($"job:{jobId}"),
                "Fetched",
                JobHelper.SerializeDateTime(DateTime.UtcNow));

            // Checkpoint #2. The job is in the implicit 'Fetched' state now.
            // This state stores information about fetched time. The job will
            // be re-queued when the JobTimeout will be expired.

            return(new RedisFetchedJob(_storage, Redis, jobId, queueName));
        }
        /// <summary>
        /// 拉取下一个作业
        /// </summary>
        /// <param name="queues">队列数组</param>
        /// <param name="cancellationToken">取消令牌</param>
        public override IFetchedJob FetchNextJob([NotNull] string[] queues, CancellationToken cancellationToken)
        {
            if (queues == null)
            {
                throw new ArgumentNullException(nameof(queues));
            }

            string jobId     = null;
            string queueName = null;

            do
            {
                cancellationToken.ThrowIfCancellationRequested();

                foreach (var queue in queues)
                {
                    queueName = queue;
                    var queueKey   = _storage.GetRedisKey($"queue:{queueName}");
                    var fetchedKey = _storage.GetRedisKey($"queue:{queueName}:dequeued");
                    jobId = RedisClient.RPopLPush(queueKey, fetchedKey);
                    if (jobId != null)
                    {
                        break;
                    }
                }

                if (jobId == null)
                {
                    _subscription.WaitForJob(_fetchTimeout, cancellationToken);
                }
            } while (jobId == null);

            RedisClient.HSet(_storage.GetRedisKey($"job:{jobId}"), "Fetched", JobHelper.SerializeDateTime(DateTime.UtcNow));

            return(new RedisFetchedJob(_storage, RedisClient, jobId, queueName));
        }