Reputation: 2546
I am using a Blockingcollection
as a FIFO queue
but I am doing a lot of operations on files, where the consumer
may easily encounter a file lock, so what I have done is created a simple try catch where the consumer re-queue's itself, but in a long FIFO queue
with lots of other Items in the queue this is enough of a pause, but in an empty or very short FIFO queue
it means the consumer
perpetually hammers the queue with repeating re-occurrences of itself that are probably going to be still file locked.
i.e.
consumer busy
-> requeue -> consumer busy
-> requeue (ad infinitum)
is there a way to get the BlockingCollection
to not attempt to run the new consumer if it is less than 10 seconds old? i.e. potentially get the net one in the queue and carry on and only take the next consumer if it's createdDateTime is null (default for first attempt) or if it is > 10 seconds?
Upvotes: 2
Views: 460
Reputation: 111870
You could keep two blocking collections: the main one and the "delayed" one. One worker thread would only work on the delayed one, readding them to the main collection. The signature of the rejected collection would be something like:
BlockingCollection<Tuple<DateTime, YourObject>>
now... If the time is fixed at 10 seconds, the delayed collection will nearly be DateTime
sorted (in case of items added nearly at the same time this could be not-true, but we are speaking of milliseconds difference... not a problem)
public class MainClass
{
// The "main" BlockingCollection
// (the one you are already using)
BlockingCollection<Work> Works = new BlockingCollection<Work>();
// The "delayed" BlockingCollection
BlockingCollection<Tuple<DateTime, Work>> Delayed = new BlockingCollection<Tuple<DateTime, Work>>();
// This is a single worker that will work on the Delayed collection
// in a separate thread
public void DelayedWorker()
{
Tuple<DateTime, Work> tuple;
while (Delayed.TryTake(out tuple, -1))
{
var dt = DateTime.Now;
if (tuple.Item1 > dt)
{
Thread.Sleep(tuple.Item1 - dt);
}
Works.Add(tuple.Item2);
}
}
}
Upvotes: 2
Reputation: 171178
There's nothing built-in to help with that. Store with each work item the DateTime
when it was last attempted (could be null
if this is the first attempt). Then, in your processing function wait for TimeSpan.FromSeconds(10) - (DateTime.UtcNow - lastAttemptDateTime)
seconds before making the next attempt.
Consider switching to a priority queue that stores items in the order of earliest next attempt datetime.
Upvotes: 3