rabbitmq-dotnet-client
rabbitmq-dotnet-client copied to clipboard
Investigate if timing out continuations can be mixed with async protocol methods
This is recurring question that pops up every year or two, most recently in #402.
The protocol has two types of methods:
- Synchronous: require a response, e.g.
queue.declare - Asynchronous: don't have a response, e.g.
basic.publishorbasic.ack
Currently continuations that hit a failure (e.g. a timeout) can't be mixed with asynchronous methods in practice. It would be nice to investigate whether that'd be possible without significant implementation changes that carry the risk of subtle concurrency semantics changes.
Specifically the following two scenarios:
* A synchronous method that fails
* An asynchronous method
* An asynchronous method that fails
* A synchronous method
Note that in practice many types of continuation failure will result in a connection recovery sequence, and thus newly opened channel(s), so a way to test this in isolation would be highly desired.
We may want to make up our mind and investigate #83, #356 first.
Not sure I fully understand, but the blockingCell can expose a WaitForValueAsync like below:
public class BlockingCellNew<T>
{
private readonly TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<T>();
public void ContinueWithValue(T value)
{
taskCompletionSource.SetResult(value);
}
public async Task<T> WaitForValueAsync(TimeSpan timeout)
{
if (taskCompletionSource.Task != await Task.WhenAny(taskCompletionSource.Task, Task.Delay(timeout)))
taskCompletionSource.SetException(new TimeoutException());
return taskCompletionSource.Task.Result;
}
///<summary>Retrieve the cell's value, waiting for the given
///timeout if no value is immediately available.</summary>
///<remarks>
///<para>
/// If a value is present in the cell at the time the call is
/// made, the call will return immediately. Otherwise, the
/// calling thread blocks until either a value appears, or
/// operation times out.
///</para>
///<para>
/// If no value was available before the timeout, an exception
/// is thrown.
///</para>
///</remarks>
/// <exception cref="TimeoutException" />
public T WaitForValue(TimeSpan timeout)
{
if (!taskCompletionSource.Task.Wait(timeout))
taskCompletionSource.SetException(new TimeoutException());
return taskCompletionSource.Task.Result;
}
///<summary>Retrieve the cell's value, waiting for the given
///timeout if no value is immediately available.</summary>
///<remarks>
///<para>
/// If a value is present in the cell at the time the call is
/// made, the call will return immediately. Otherwise, the
/// calling thread blocks until either a value appears, or
/// operation times out.
///</para>
///<para>
/// If no value was available before the timeout, an exception
/// is thrown.
///</para>
///</remarks>
/// <exception cref="TimeoutException" />
public T WaitForValue(int timeout)
{
return WaitForValue(TimeSpan.FromMilliseconds(timeout));
}
///<summary>Retrieve the cell's value, blocking if none exists
///at present, or supply a value to an empty cell, thereby
///filling it.</summary>
/// <exception cref="TimeoutException" />
public T WaitForValue()
{
return WaitForValue(TimeSpan.FromMinutes(60));
}
///<summary>Return valid timeout value</summary>
///<remarks>If value of the parameter is less then zero, return 0
///to mean infinity</remarks>
public static int validatedTimeout(int timeout)
{
return (timeout != Timeout.Infinite) && (timeout < 0) ? 0 : timeout;
}
}
Is this an issue that should be evaluated for version 6.0 or left alone for now? @michaelklishin @kjnilsson
Moving to version 7.0.0 milestone.
https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/1368