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