Task.Run() & Task.Delay() terminated after sometime - c#

I have created windows service in c# and in that service, I have created 4 threads and running them the background every after 10 sec.
Below is the code:
var ThreadSize = 4;
for (int i = 0; i < ThreadSize; i++)
{
Task.Run(async () =>
{
while (1 == 1)
{
try
{
//Logic
await Task.Delay(10000, cancelSource.Token);
}
catch (Exception ex)
{
//Log the exception
}
}
});
}
The for loop will be executed only once and will create 4 threads. I am using Task.Delay to wait the thread for 10 sec and then again executing my logic. It will go and execute my logic every 10 sec.
The code is working fine, but after some time, my all threads getting terminated (Not working). I mean, the code in the logic is not working after couples of hours.
There is no exception at all.
Can any one suggested what went wrong.
Thanks you in advance.
Edited Code:
CancellationTokenSource cancelSource;
protected override void OnStart(string[] args)
{
cancelSource = new CancellationTokenSource();
Process.StartProcess(cancelSource);
}
protected override void OnStop()
{
cancelSource.Cancel();
}
public static void StartProcess(CancellationTokenSource cancelSource)
{
var ThreadSize = 4;
for (int i = 0; i < ThreadSize; i++)
{
Task.Run(async () =>
{
while (1 == 1)
{
try
{
//Logic
await Task.Delay(10000, cancelSource.Token);
}
catch (Exception ex)
{
//Log the exception
}
}
});
}
}

If any exception occurs within the Task.Run, it will be saved and thrown when the task is awaited. You're not awaiting the task, so any exception that has occurred won't be visible.
You should await the Task.Run by either using the await keyword or call .Wait() on it.
As you're spawning multiple tasks, you could add all of them to a list and then call await Task.WhenAny(tasks) which will return when any of the tasks finishes, so you can act accordingly.
Read this article for more information

Your main problem is in
catch (Exception ex)
{
throw;
}
This effectively means that you don't catch any errors. You might as well remove the try/catch for the same effect, or lack of effect.
The main structure of your Service looks OK, this won't stop by itself. The choice of Task vs Thread is not too important.
Your error happens inside //Logic and is not handled.
You will need some form of logging to find out.

Related

Az function chaining with unsuccessful Fan-out/fan-in run on the first step

I wonder how can I make Function2 run if one the Function1 fails in Fan-out/fan-in scenario:
var tasks = new Task<long>[files.Length];
for (int i = 0; i < files.Length; i++)
{
// if one of the function fails with Exception,
// orchestrator execution does not pass Task.WhenAll(tasks) point, but I want it to.
tasks[i] = backupContext.CallActivityAsync<long>(
"Function1", files[i]);
}
await Task.WhenAll(tasks);
// how to reach this point if one of the task throws exception?
await context.CallActivityAsync("Function2", null);
In other words, I want to wait all Function1 to get completed, whether it's success or not, and then run Function2.
If I wrap await Task.WhenAll(tasks); in the try{} catch{} block it does not catch the exception if one of the task is successful and runs long enough (longer than task throwing exception), ran many experiments upon it.
UPDATE
If I wrap tasks execution in try{} catch{}
try
{
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
}
and Function1 looks like this
public async Task RunSubOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)
{
if (context.GetInput<string>() == "instanceToFail")
{
throw new Exception("TestException");
}
// this is what instanceToSucced executes
int delayInSec = 0;
await Task.Delay(delayInSec * 1000);
}
catch block hits, but once I set int delayInSec = 180 it never hits, tried it many times. If successful instance overlives failed one, exception is not thrown in the orchestrator. I run Azure Functions 3
I wonder how can I make Function2 run if one the Function1 fails
You can deal with the error handling in your activity function and if it fails you can handle the error and return the response accordingly to run another activity function in your orchestration.
Handling Error in Activity Function
public static async Task<int> FunctionListResult([ActivityTrigger] int value, ILogger log)
{
try
{
var myOutputData = await DoSomething(value);
return new
{
int delayInsec = 0;
return await Task.FromResult(delayInsec * 1000);
}
}Catch(Exception Ex)
{
// Handle the exception ...
Dosomething();
return new
{
Success = false,
ErrorMessage = Ex.Message
};
}
If an activity function fails with the respective values, you can call the other activity with that information. For better handling error you can handle the error meaningfully in activity function and return the value accordingly for your orchestration.
Handling in orchestration
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
try
{
var details = ctx.GetInput<value>();
await context.CallActivityAsync("FunctionListResult", value);
}
catch (FunctionFailedException)
{
var otherDetails = GetOtherInput(< some value >);
await context.CallActivityAsync("FunctionListResult", somevalue);
}
}
Whenever we were not handling the error, the exceptions are logged, and instance completes with a failed status.

Recursively call a method with the same thread

I have the following method:
public async Task ScrapeObjects(int page = 1)
{
try
{
while (!isObjectSearchCompleted)
{
..do calls..
}
}
catch (HttpRequestException ex)
{
Thread.Sleep(TimeSpan.FromSeconds(60));
ScrapeObjects(page);
Log.Fatal(ex, ex.Message);
}
}
I call this long running method async and I don't wait for it to finish. Thing is that an exception my occur and in that case I want to handle it. But then I want to start from where I left and with the same thread. At the current state a new thread gets used when I recursively call the method after handling the exception. I would like to keep using the same thread. Is there a way to do so? Thank you!
You probably need to move the try/catch block inside the while loop, and add a counter with the errors occurred, to bail out in case of continuous faulted attempts.
public async Task ScrapeObjects()
{
int failedCount = 0;
int page = 1;
while (!isObjectSearchCompleted)
{
try
{
//..do calls..
}
catch (HttpRequestException ex)
{
failedCount++;
if (failedCount < 3)
{
Log.Info(ex, ex.Message);
await Task.Delay(TimeSpan.FromSeconds(60));
}
else
{
Log.Fatal(ex, ex.Message);
throw; // or return;
}
}
}
}
As a side note it is generally better to await Task.Delay instead of Thread.Sleep inside asynchronous methods, to avoid blocking a thread without a reason.
One simple question before you read the long answer below:
Why you need the same thread? Are you accessing thread static / contextual data?
If yes, there will be ways to solve that easily than limiting your tasks to run on the same thread.
How to limit tasks to run on a single thread
As long as you use async calls on the default synchronization context, and as soon as the code is resumed from an await, it is possible that the thread can change after an await. This is because the default context schedules tasks to the next available thread in the thread pool. Like in the below case, before can be different from after:
public async Task ScrapeObjects(int page = 1)
{
var before = Thread.CurrentThread.ManagedThreadId;
await Task.Delay(1000);
var after = Thread.CurrentThread.ManagedThreadId;
}
The only reliable way to guarantee that your code could come back on the same thread is to schedule your async code onto a single threaded synchronization context:
class SingleThreadSynchronizationContext : SynchronizationContext
{
private readonly BlockingCollection<Action> _actions = new BlockingCollection<Action>();
private readonly Thread _theThread;
public SingleThreadSynchronizationContext()
{
_theThread = new Thread(DoWork);
_theThread.IsBackground = true;
_theThread.Start();
}
public override void Send(SendOrPostCallback d, object state)
{
// Send requires run the delegate immediately.
d(state);
}
public override void Post(SendOrPostCallback d, object state)
{
// Schedule the action by adding to blocking collection.
_actions.Add(() => d(state));
}
private void DoWork()
{
// Keep picking up actions to run from the collection.
while (!_actions.IsAddingCompleted)
{
try
{
var action = _actions.Take();
action();
}
catch (InvalidOperationException)
{
break;
}
}
}
}
And you need to schedule ScrapeObjects to the custom context:
SynchronizationContext.SetSynchronizationContext(new SingleThreadSynchronizationContext());
await Task.Factory.StartNew(
() => ScrapeObjects(),
CancellationToken.None,
TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext()
).Unwrap();
By doing that, all your async code shall be scheduled to the same context, and run by the thread on that context.
However
This is typically dangerous, as you suddenly lose the ability to use the thread pool. If you block the thread, the entire async operation is blocked, meaning you will have deadlocks.

C# event exception not caught in parent method

I`m working on implementing a get method for cache. This method will return to caller if a maximum wait time has passed(in my case 100ms for tests).
My issue is that the exception NEVER reaches the catch, after the timer triggered the event.
Please help me understand why? (I read that events are executed on the same thread, so that should`t be the issue)
public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
{
var result = default(T);
try
{
// Return default if time expired
if (maxMilisecondsForResponse.HasValue)
{
var timer = new System.Timers.Timer(maxMilisecondsForResponse.Value);
timer.Elapsed += OnTimerElapsed;
timer.AutoReset = false;
timer.Enabled = true; // start the timer
}
var externalCache = new CacheServiceClient(BindingName);
Thread.Sleep(3000); // just for testing
}
catch (Exception ex)
{
// why is the exception not caught here?
}
return result;
}
private static void OnTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{
throw new Exception("Timer elapsed");
}
The timer fires on it's own thread. You can read more about it in this answer.
The answer to your question is to use async methods that can be cancelled. Then you can use a cancellation token source and do it the proper way instead of homebrewing a solution with timers.
You can find a good overview here.
For example:
cts = new CancellationTokenSource();
cts.CancelAfter(2500);
await Task.Delay(10000, cts.Token);
This would cancel the waiting task after 2500 (of 10000) because it took too long. Obviously you need to insert your own logic in a task instead of just waiting.
From MSDN
The Timer component catches and suppresses all exceptions thrown by
event handlers for the Elapsed event. This behavior is subject to
change in future releases of the .NET Framework.
And continues
Note, however, that this is not true of event handlers that execute
asynchronously and include the await operator (in C#) or the Await
operator (in Visual Basic). Exceptions thrown in these event handlers
are propagated back to the calling thread.
Please take a look Exception Handling (Task Parallel Library)
An applied example below:
public class Program
{
static void Main()
{
Console.WriteLine("Begin");
Get<string>("key", 1000);
Console.WriteLine("End");
}
public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
{
var result = default(T);
try
{
var task = Task.Run(async () =>
{
await Task.Delay(maxMilisecondsForResponse.Value);
throw new Exception("Timer elapsed");
});
task.Wait();
}
catch (Exception ex)
{
// why the exception is not catched here?
Console.WriteLine(ex);
}
return result;
}
}
The timer is being executed in the own thread but you can't catch the exception at the caller level. So, it is not a good approach to use timer in this case and you can change it by creating the Task operation.
var result = default(T);
CacheServiceClient externalCache;
if (!Task.Run(() =>
{
externalCache = new CacheServiceClient(BindingName);
return externalCache;
}).Wait(100))//Wait for the 100 ms to complete operation.
{
throw new Exception("Task is not completed !");
}
// Do something
return result;

Try-Catch inside while loop exits after first Exception

I have a Windows service that runs the following Initialize() method immediately after being instantiated.
public async virtual void Initialize()
{
bool initSuccess = false;
int retry = 1;
while (!initSuccess && retry <= 10)
{
try
{
schedulerFactory = CreateSchedulerFactory();
scheduler = GetScheduler();
initSuccess = true;
}
catch (Exception ex)
{
logger.Error(string.Format("Server initialization failed, retry #{0} of 10 / Error message: {1}", retry, ex.Message));
retry++;
}
Task startTimer = Task.Factory.StartNew(() =>
{
Thread.Sleep(10000);
});
await startTimer;
}
}
So if the initialization fails, I would like to give the server 10 more tries to start. The code that calls the above function is:
QuartzServer server = new QuartzServer();
server.Initialize();
return server;
For some reason, this Initialize() method quits after the first iteration. That means my while loop seems the be useless although I can see in my log that the Exception is caught. Can anyone detect anything wrong with the logic of the code?
Initialize is an async void method, which normally should be avoided and only be used for event handlers. The reason is that it's impossible to wait for completion for such a method since it doesn't return a Task. The first time you reach the await startTimer statement Initialize will return control to its caller so it looks like the while loop has been exited, when in fact it hasn't.

Exception is not caught at Cancelation of Task.Run

I have a class Worker which is doing some work (with simulated workload):
public class Worker
{ ...
public void DoWork(CancellationToken ct)
{
for (int i = 0; i < 10; i++)
{
ct.ThrowIfCancellationRequested();
Thread.Sleep(2000);
}
}
Now I want to use this method in a Task.Run (from my Windows Forms App,at button-click) which can be cancelled:
private CancellationTokenSource _ctSource;
try
{
Task.Run(() =>
{
_worker.DoWork(_ctSource.Token);
},_ctSource.Token);
}
catch (AggregateException aex)
{
String g = aex.Message;
}
catch (OperationCanceledException ex)
{
String g = ex.Message;
}
catch (Exception ex)
{
String g = ex.Message;
}
But when the task is started, I can't cancel it with _ctSource.Cancel();
I get an error in visual studio that the OperationCanceledException is not handled!
But I surrounded the Task.Run Call in a try-catch-clause! The Exception which ocurrs in the Worker object should thrown up or not?
What is the problem?
Your Task.Run call creates the task and then returns immediately. It doesn't ever throw. But the task it creates may fail or be canceled later on.
You have several solutions here:
Use await:
await Task.Run(...)
Attach a continuation depending on the failure/cancellation case:
var task = Task.Run(...);
task.ContinueWith(t => ..., TaskContinuationOptions.OnlyOnCanceled);
task.ContinueWith(t => ..., TaskContinuationOptions.OnlyOnFaulted);
Attach a single continuation on failure:
Task.Run(...).ContinueWith(t => ..., TaskContinuationOptions.NotOnRanToCompletion);
The solution you can/should use depends on the surrounding code.
You need to new the token
private CancellationTokenSource _ctSource = new CancellationTokenSource();
Why are throwing an expectation in DoWork?
Exception from one thread don't bubble up another thread that started the thread.
Cancellation in Managed Threads
If a parallel Task throws an exception it'll return execution and will have it's Exception property (as an AggregateException, you should check for its InnerException) set (and either its IsCanceled or IsFaulted property set to true). Some minimal sample code from a project of mine which escalates the exception to the main thread:
var t = new Task(Initialize);
t.Start();
while (!t.IsCompleted && !t.IsFaulted)
{
// Do other work in the main thread
}
if (t.IsFaulted)
{
if (t.Exception != null)
{
if(t.Exception.InnerException != null)
throw t.Exception.InnerException;
}
throw new InvalidAsynchronousStateException("Initialization failed for an unknown reason");
}
If you use a CancellationTokenSource it should be easy to enhance this to check for IsCanceled (instead of IsFaulted)
You can also use Task.Wait() instead of the while loop... in my project and in that precise case it seemed more appropiate to use the while loop, but you need to wait for the Task to end in one way or another.
If you use Task.Run() you can use a .ContinueWith(Task) which will have the original task passed in (where you can check for IsFaulted or IsCanceled), or have it run only on faulted execution, at your will.

Categories

Resources