I have below code which is executed by two tasks and I am reproducing the behavior where two transactions are in flight and try to dequeue an item from the reliable queue.
using (var tx = stateManager.CreateTransaction())
{
LogInfo("{0} Dequeueing at {1}", taskName, DateTime.Now.ToString("hh.mm.ss.ffffff")));
ConditionalValue<int> result1 = await items.TryDequeueAsync(tx);
LogInfo("{0} Dequeued at {1}", taskName, DateTime.Now.ToString("hh.mm.ss.ffffff")));
if (task == "Task1")
{
await Task.Delay(4000);
}
else if (task == "Task2")
{
// Do nothing
}
await tx.CommitAsync();
}
I fire Task1 first and then after 1 second delay fire Task2. Task1 dequeues and waits for 4 seconds. While it is waiting, Task2 begins the transaction and tries to dequeue. However, it gets blocked till Task1 transaction completes.
But the documentation says like below:
Transaction is the unit of concurrency: Users can have multiple transactions
in-flight at any given point of time but for a given transaction each API
must be called one at a time. So all Reliable Collection APIs that take in a
transaction and return a Task, must be awaited one at a time
In my case, I am calling dequeue for both tasks at different times but still it gets blocked. Is my understanding correct? Or I am doing something wrong in the code?
IReliableQueue has some different behavior because it is strictly First In First Out (FIFO). For instance, if you abort the transaction for Task1, the item will remain at the top of the queue. If they allowed Task2 to succeed, then the queue order would not be preserved and you would have successfully removed the second item from the queue rather than the first. There are a number of locking issues with an IReliableQueue because of this FIFO behavior.
If you don't care about order, use ReliableConcurrentQueue. See this article for more details between the two queue types.