How to close the Azure ServiceBus QueueClient gracefully? - c#

When I call QueueClient.Close(), it always raises an exception:
The operation cannot be performed because the entity has been closed
or aborted.
It raises the exception, even if the queue was empty.
Although I handle it by using OnMessageOptions.ExceptionReceived, but it's annoying me. Is there something wrong with my code?
How to stop the QueueClient gracefully?
[Start, and stop the messaging]
// create a QueueClient with Exception handler.
var queueClient = queueManager.GetStorage<UpdateTriggerQueueClient>();
var options = new OnMessageOptions
{
AutoComplete = false
};
// When the Close() called, it always handles an exception.
options.ExceptionReceived += (sender, args) =>
logger.Error("An excepion occurred.", args.Exception);
// prepare a CancellationTokenSource.
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
// start message pump.
queueClient.OnMessageAsync(async message =>
await DoWork(message, cancellationToken), options);
// sometime after, stop(cancel) the work.
Task.Delay(5000).Wait();
cancellationTokenSource.Cancel();
// some code to wait every in-progress messages finished.
// ...
// close the client.
queueClient.Close();
[DoWork method]
private async Task DoWork(BrokeredMessage message, CancellationToken cancellationToken)
{
logger.Trace("begin work");
// Do something cancellable work.
await Task.Delay(500, cancellationToken)
.ContinueWith(async t =>
{
// complete the message when the task completed,
// otherwise, abandon the message.
if (t.Status == TaskStatus.RanToCompletion)
{
await message.CompleteAsync();
}
else
{
await message.AbandonAsync();
}
})
.ContinueWith(t =>
{
// cleanup
logger.Trace("end work");
});
}

You can stop all messages from being recieved by updating the subscription with:
_namespaceManager.UpdateSubscription(new SubscriptionDescription(_strTopic, _strSubscription)
{
Status = EntityStatus.ReceiveDisabled
});
This may solve your problem even though it's not exactly what you're asking. (I'm also trying to find out how to close() properly.
You will also need to update the status to begin receiving again.

I think it is important to understand how the IQueueClient interface works. When you receive a message you receive what is called a CancellationToken. The CancellationToken enables you to cooperate a cancellation between threads, thread pool work items, or Task object. In this case you need to handle Azure Service Bus connection. This is what I will do, control if the connection has been closed, if that is the case, I will check if the message we have received still alive.
public async Task<object> ReceiveAsync(Message message, CancellationToken token)
{
//If the connection still open, we do something
if (!token.IsCancellationRequested)
{
...
}
}

I read on https://msdn.microsoft.com/en-us/library/azure/hh528527.aspx that close should not be called as the connection is managed by the message factories.
this.mSubscriptionClient.OnMessage(
(pMessage) =>
{
try
{
// Will block the current thread if Stop is called.
this.mPauseProcessingEvent.WaitOne();
// Execute processing task here
pProcessMessageTask(pMessage);
}
catch(Exception ex)
{
this.RaiseOnLogMessageEvent(pMessage, ex);
}
},
options);
And then when you are ready to stop
this.mPauseProcessingEvent.Reset();
mSubscriptionClient.Close();
The datatype is
private ManualResetEvent mPauseProcessingEvent;

Related

IsCancellationRequested is always false if CancellationTokenSource with delay

I try to stop process by CancellationToken with timer.
But IsCancellationRequested is always false.
I tried to call cancellationToken.ThrowIfCancellationRequested(); it doesn't work.
public async Task<IReadOnlyList<ISearchableDevice>> SearchAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(100, cancellationToken);
cancellationToken.ThrowIfCancellationRequested(); // doesn't work
}
IReadOnlyList<ISearchableDevice> devices = new List<ISearchableDevice>();
return devices;
}
private void OnStartSearchCommandExecuted(object? p)
{
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3)))
{
try
{
InProgress = true;
DeviceSearcher.SearchAsync(cts.Token)
.ContinueWith(task =>
{
InProgress = false;
}, cts.Token);
}
catch (Exception)
{
// TODO: Add exception handling
}
}
}
Where is the mistake?
The problem is that cts is disposed before timeout is reached. More precisely, it is disposed immediately after SearchAsync reaches first await.
You have at least two ways to solve this
Use await DeviceSearcher.SearchAsync instead of DeviceSearcher.SearchAsync().ContinueWith(). This is the best way, but it will force you to make the OnStartSearchCommandExecuted async.
Remove using block and call Dispose manually inside .ContinueWith (and move other post-searh logic inside ContinueWith and also do not forget call Dispose in case of exceptions (whether exception will occur in synchronous part of SearchAsync (before first await) or in asynchronous part. )).

How to handle cancellationToken.cancel for Task.delay in c#?

I have an method in which I am using Task.Delay for 1 minute. So when I want to try cancel that Task then it's giving me error like system.threading.tasks.taskcanceledexception a task was canceled instead of cancel that Task.
So how can I cancel that Task with handle this error.
public static System.Threading.CancellationTokenSource tokenSource = new System.Threading.CancellationTokenSource();
tokenSource.cancel();
public static async void waitForSignal(System.Threading.CancellationToken token)
{
await Task.Delay(60000, token); //here I am getting error while I am defining tokenSource cancel.
}
So how can I cancel that Task with handle this error.
You're already canceling the task; you just need to handle the error:
try
{
await Task.Delay(60000, token);
}
catch (OperationCanceledException)
{
}
...
Actually admin is getting signals from wcf service in which if admin will not get expected signals from wcf then it will wait for 60 seconds and if admin will get expected numbers of signals in first 10 seconds then it will not required to wait for next 50 seconds.
Sounds like what you want is a signal, not a cancellation. You want to (asynchronously) wait for either a signal or a time period (delay), after which you want to take some action. You don't really want cancellation here.
One kind of asynchronous signal is TaskCompletionSource<T>. Your action code can await the Task of that TCS, and the signaling code can call SetResult to send the signal. Something like this:
public static TaskCompletionSource<object> signal = new TaskCompletionSource<object>();
...
signal.SetResult(null);
...
public static async Task waitForSignal(Task signalTask)
{
await Task.WhenAny(Task.Delay(60000), signalTask);
}

How Do I Create a Looping Service inside an C# Async/Await application?

I have written a class with a method that runs as a long-running Task in the thread pool. The method is a monitoring service to periodically make a REST request to check on the status of another system. It's just a while() loop with a try()catch() inside so that it can handle its own exceptions and and gracefully continuing if something unexpected happens.
Here's an example:
public void LaunchMonitorThread()
{
Task.Run(() =>
{
while (true)
{
try
{
//Check system status
Thread.Sleep(5000);
}
catch (Exception e)
{
Console.WriteLine("An error occurred. Resuming on next loop...");
}
}
});
}
It works fine, but I want to know if there's another pattern I could use that would allow the Monitor method to run as regular part of a standard Async/Await application, instead of launching it with Task.Run() -- basically I'm trying to avoid fire-and-forget pattern.
So I tried refactoring the code to this:
public async Task LaunchMonitorThread()
{
while (true)
{
try
{
//Check system status
//Use task.delay instead of thread.sleep:
await Task.Delay(5000);
}
catch (Exception e)
{
Console.WriteLine("An error occurred. Resuming on next loop...");
}
}
}
But when I try to call the method in another async method, I get the fun compiler warning:
"Because this call is not awaited, execution of the current method continues before the call is completed."
Now I think this is correct and what I want. But I have doubts because I'm new to async/await. Is this code going to run the way I expect or is it going to DEADLOCK or do something else fatal?
What you are really looking for is the use of a Timer. Use the one in the System.Threading namespace. There is no need to use Task or any other variation thereof (for the code sample you have shown).
private System.Threading.Timer timer;
void StartTimer()
{
timer = new System.Threading.Timer(TimerExecution, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
}
void TimerExecution(object state)
{
try
{
//Check system status
}
catch (Exception e)
{
Console.WriteLine("An error occurred. Resuming on next loop...");
}
}
From the documentation
Provides a mechanism for executing a method on a thread pool thread at specified intervals
You could also use System.Timers.Timer but you might not need it. For a comparison between the 2 Timers see also System.Timers.Timer vs System.Threading.Timer.
If you need fire-and-forget operation, it is fine. I'd suggest to improve it with CancellationToken
public async Task LaunchMonitorThread(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
try
{
//Check system status
//Use task.delay instead of thread.sleep:
await Task.Delay(5000, token);
}
catch (Exception e)
{
Console.WriteLine("An error occurred. Resuming on next loop...");
}
}
}
besides that, you can use it like
var cancellationToken = new CancellationToken();
var monitorTask = LaunchMonitorThread(cancellationToken);
and save task and/or cancellationToken to interrupt monitor wherever you want
The method Task.Run that you use to fire is perfect to start long-running async functions from a non-async method.
You are right: the forget part is not correct. If for instance your process is going to close, it would be neater if you kindly asked the started thread to finish its task.
The proper way to do this would be to use a CancellationTokenSource. If you order the CancellationTokenSource to Cancel, then all procedures that were started using Tokens from this CancellationTokenSource will stop neatly within reasonable time.
So let's create a class LongRunningTask, that will create a long running Task upon construction and Cancel this task using the CancellationTokenSource upon Dispose().
As both the CancellationTokenSource as the Task implement IDisposable the neat way would be to Dispose these two when the LongRunningTask object is disposed
class LongRunningTask : IDisposable
{
public LongRunningTask(Action<CancellationToken> action)
{ // Starts a Task that will perform the action
this.cancellationTokenSource = new CancellationTokenSource();
this.longRunningTask = Task.Run( () => action (this.cancellationTokenSource.Token));
}
private readonly CancellationTokenSource cancellationTokenSource;
private readonly Task longRunningTask;
private bool isDisposed = false;
public async Task CancelAsync()
{ // cancel the task and wait until the task is completed:
if (this.isDisposed) throw new ObjectDisposedException();
this.cancellationTokenSource.Cancel();
await this.longRunningTask;
}
// for completeness a non-async version:
public void Cancel()
{ // cancel the task and wait until the task is completed:
if (this.isDisposed) throw new ObjectDisposedException();
this.cancellationTokenSource.Cancel();
this.longRunningTask.Wait;
}
}
Add a standard Dispose Pattern
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (disposing && !this.isDisposed)
{ // cancel the task, and wait until task completed:
this.Cancel();
this.IsDisposed = true;
}
}
Usage:
var longRunningTask = new LongRunningTask( (token) => MyFunction(token)
...
// when application closes:
await longRunningTask.CancelAsync(); // not necessary but the neat way to do
longRunningTask.Dispose();
The Action {...} has a CancellationToken as input parameter, your function should regularly check it
async Task MyFunction(CancellationToken token)
{
while (!token.IsCancellationrequested)
{
// do what you have to do, make sure to regularly (every second?) check the token
// when calling other tasks: pass the token
await Task.Delay(TimeSpan.FromSeconds(5), token);
}
}
Instead of checking for Token, you could call token.ThrowIfCancellationRequested. This will throw an exception that you'll have to catch

C# How to handle cancel task with eventhandler inside

I have requirement to update ui control when status of dependent service will change. I have this sample code, which polling service api to get status and sends result to recalculate and update ui by main thread:
public void StartObserving() {
this.cts = new CancellationTokenSource();
this.cts.Token.ThrowIfCancellationRequested();
this.isRunning = true;
var token = this.cts.Token;
Task.Run(async () =>
{
try
{
while (this.isRunning)
{
var result = this.serviceAPI.GetStatus();
this.OnServiceStatusChanged(result);
await Task.Delay(3000);
}
}
catch (OperationCanceledException)
{
this.isRunning = false;
}
catch (Exception ex)
{
this.isRunning = false;
this.logger.LogError(ex);
}
}, token);
}
And the problem is when I want to cancel above Task. When I call this.cts.Cancel() in another method in this class, I get Exception 'A task was canceled' on dispatcher which was triggered by EventHandler: OnServiceStatusChanged
How I should properly implement this scenario?
I would simply check whether the token in cancelled in the inner loop, and exit the loop if it is. No need to pass the token to the Task.Run() method.
public void StartObserving()
{
this.cts = new CancellationTokenSource();
var token = this.cts.Token;
Task.Run(async () =>
{
try
{
while (!token.IsCancellationRequested)
{
var result = this.serviceAPI.GetStatus();
this.OnServiceStatusChanged(result);
await Task.Delay(3000);
}
}
catch
{
}
});
}
Tried to simulate this behavior in a console app. Task started, but after calling cts.Cancel(), the task continues to execute... Very strange.
However, I could cancel the task by simply setting this.isRunning to false (instead of calling cts.Cancel()). But I am not sure if this is the solution you want.
If serviceAPI.GetStatus() is a blocking call that waits indeffinitly, then you cannot properly cancel this task.
Proper cancellation of async methods involves marking safe cancellation points with CancellationToken.ThrowIfCancellationRequested().
You would have to rewrite serviceAPI.GetStatus() as an async method that you await the result of. It should contain calls to CancellationToken.ThrowIfCancellationRequested() at points where it can be safely cancelled. You would want to pass the cancellation token in to both that method, and the call to Task.Delay() for optimal performance.

TcpClient.ConnectAsync or Socket.BeginConnect with non-blocking timeout setting

All solutions I found so far are based on WaitOne:
How to configure socket connect timeout
or spawning a worker thread
For me, blocking the thread with WaitOne defeats the purpose of async methods. Spawning another thread is not much better (as async model strives to use as less threads as possible).
Is there any other solution which would still let me abort the connection attempt without blocking the current thread or spawning another one?
I'm developing a library used by external code which has no knowledge of what's going on inside my library (the code just calls my ConnectAsync method and I do the rest including TcpClient.ConnectAsync and so on). The external code can be anything (web app, desktop app, Windows service, whatever). Ideally, the solution should not require the external code to do anything to abort the operation beyond setting .Timeout property of my class. However, if it's the only the way to avoid blocks or worker threads when implementing custom connection timeout, I'd be grateful to see which options I have (in terms of async/await model).
TcpClient.SendAsync doesn't receive a CancellationToken so it can't really be canceled (How do I cancel non-cancelable async operations?). You can use the WithTimeout extensions method:
public static Task<TResult> WithTimeout<TResult>(this Task<TResult> task, TimeSpan timeout)
{
var timeoutTask = Task.Delay(timeout).ContinueWith(_ => default(TResult), TaskContinuationOptions.ExecuteSynchronously);
return Task.WhenAny(task, timeoutTask).Unwrap();
}
This doesn't cancel the original operation though, only allows your code to behave as if it did. The abandoned operation will linger forever unless handled explicitly.
To actually cancel the underlying operation you should make sure to call Dispose on the TcpClient (preferably via a using scope). That would make the abandoned task throw an ObjectDisposedException (or others) so be aware of that.
You can take a look at my answer here about using a TimeoutScope:
try
{
var client = new TcpClient();
using (client.CreateTimeoutScope(TimeSpan.FromSeconds(2)))
{
var result = await client.ConnectAsync();
// Handle result
}
}
catch (ObjectDisposedException)
{
return null;
}
If you create a second task for the timeout (Task.Delay does nicely), then you can use Task.WhenAny to complete as soon as either your task, or the timeout completes.
var timeout = Task.Delay(whatever);
var mightTimeout = Task.WhenAny(new {} { timeout, originalTask });
// let mightTimeout complete by whatever method (eg. async)
if (mightTimeout == timeout) {
// Timeout!!
// Put abort code in here.
}
I found a solution using
Await Task.WhenAny
Task.WhenAny will finish whenever any of the task included finishes first.
Put it inside an async function
Here's an example that works for me:
Public Async Function TCPConnectionAsync(HostIpAddress, Port) As Task(Of String)
Dim client As New TcpClient
Await Task.WhenAny(client.ConnectAsync(HostIpAddress, Porta), Task.Delay(3000))
'this above will not block because function is async,
'whenever the connection is successful or Task.Delay expires the task will end
' proceeding next, where you can check the connection
If client.Connected = False Then 'this will be evaluated after 3000ms
client.Close()
return "not connected"
else
'do here whatever you need with the client connection
client.Close()
return "all done"
End If
End Sub
For those who want to use asynchronous solution with async/await with timeout support:
public static async Task<bool> PingHostAndPort(string host, int port, int timeout)
{
using (var tcpClient = new TcpClient())
{
Task connectTask = tcpClient.ConnectAsync(host, port);
Task timeoutTask = Task.Delay(timeout);
// Double await is required to catch the exception.
Task completedTask = await Task.WhenAny(connectTask, timeoutTask);
try
{
await completedTask;
}
catch (Exception)
{
return false;
}
if (timeoutTask.IsCompleted)
{
return false;
}
return connectTask.Status == TaskStatus.RanToCompletion && tcpClient.Connected;
};
}
Note that you can use this logic (utilizing the timeoutTask) from any operations/methods that miss a timeout parameter.

Categories