1

I need a background queue service for my dotnet 6 application. I followed this Microsoft doc to create the bones of it.

Because of the nature of my application, it is possible for an item to be added more than once to my queue which I would like to avoid for efficiency.

Is there any way to check if the id exists in the channel before I add it? All I can find is the Channel.Reader.TryPeek() method which I don't think is able to provide what I need.

Jimmy Boy
  • 119
  • 6
  • Do you want to enforce the uniqueness of only the items that are currently stored inside the channel, or of all the items that are ever going to pass through the channel? In other words if you write the value X in the channel, and the X is consumed, is it allowed to write the value X again? – Theodor Zoulias May 24 '22 at 15:45
  • Thanks for the response. Yeah, I need to enforce the uniqueness of only what is in the channel, once the item is processed and dequeued it needs to be free to be able to go through the channel again. Based on your answer below I think I will use `ConcurrentQueue();` and queue/process using the Ids of my objects – Jimmy Boy May 25 '22 at 08:48
  • Jimmy the `ConcurrentQueue` collection offers no safe way to enqueue an item only if it's not already contained in the queue. This pattern: `if (!queue.Contains(x)) queue.Enqueue(x);` has an unavoidable race condition. See [this](https://stackoverflow.com/questions/5845241/how-to-create-no-duplicates-concurrentqueue "How to create no-duplicates ConcurrentQueue?") question. – Theodor Zoulias May 25 '22 at 08:53

1 Answers1

3

No, the built-in Channel<T> implementations don't offer this functionality. You can only peek the item that is currently in the head of the queue. All other items that are stored in the Channel<T> are not accessible, until they reach the head and can be peeked or consumed.

That said, the Channel<T> class is extensible. You could implement you own Channel<T>-derived class, and equip it with the functionality that you want. You can find an example here. This is not a trivial undertaking though, especially if you are aiming at the memory-efficiency of the built-in implementations. These are based on the IValueTaskSource<T> interface, for minimizing the memory allocations of the await operations when an item cannot be added or consumed from the channel immediately, and the producer or the consumer must wait.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104