private void Acquire(TimeSpan timeout) { var isLockAcquired = false; try { var now = DateTime.Now; var lockTimeoutTime = now.Add(timeout); while (!isLockAcquired && (lockTimeoutTime >= now)) { isLockAcquired = Acquire(); if (!isLockAcquired) { _signal.Wait($@"{nameof(MongoDistributedLock)}.{_resource}", timeout); now = DateTime.Now; } } } catch (OperationCanceledException) { // The signal wait timed out } catch (Exception ex) { throw new MongoDistributedLockException($"Could not place a lock on the resource \'{_resource}\': Check inner exception for details.", ex); } if (!isLockAcquired) { throw new DistributedLockTimeoutException( $"Could not place a lock on the resource \'{_resource}\': The lock request timed out."); } }
public IFetchedJob Dequeue(string[] queues, CancellationToken cancellationToken) { if (queues == null) { throw new ArgumentNullException(nameof(queues)); } if (queues.Length == 0) { throw new ArgumentException("Queue array must be non-empty.", nameof(queues)); } var filter = Builders <JobQueueDto> .Filter; var fetchConditions = new[] { filter.Eq(_ => _.FetchedAt, null), filter.Lt(_ => _.FetchedAt, DateTime.UtcNow.AddSeconds(_storageOptions.InvisibilityTimeout.Negate().TotalSeconds)) }; var fetchConditionsIndex = 0; var options = new FindOneAndUpdateOptions <JobQueueDto> { IsUpsert = false, ReturnDocument = ReturnDocument.After }; JobQueueDto fetchedJob = null; while (fetchedJob == null) { cancellationToken.ThrowIfCancellationRequested(); var fetchCondition = fetchConditions[fetchConditionsIndex]; foreach (var queue in queues) { fetchedJob = _database.JobQueue.FindOneAndUpdate( fetchCondition & filter.Eq(_ => _.Queue, queue), Builders <JobQueueDto> .Update.Set(_ => _.FetchedAt, DateTime.UtcNow), options, cancellationToken); if (fetchedJob != null) { break; } } if (fetchedJob == null) { // No more jobs found in any of the requested queues... if (fetchConditionsIndex == fetchConditions.Length - 1) { // ...and we are out of fetch conditions as well. // Wait for a while before polling again. var waitNames = queues.Select(q => $@"JobQueue.{q}"); _signal.Wait(waitNames.ToArray(), cancellationToken); } } // Move on to next fetch condition fetchConditionsIndex = (fetchConditionsIndex + 1) % fetchConditions.Length; } return(new MongoFetchedJob(_database, fetchedJob.Id, fetchedJob.JobId, fetchedJob.Queue)); }