Interrupt calling thread when exception in child task - c#

I have the following scenario:
I have a plugin class (unfortunately synchronous and that's out of my control) which runs automation scripts. At startup, a task is started which runs in the background continuously until the user stops it. As this task runs, it is parsing streaming incoming data from a serial port and continuously updating a list of responses. In parallel, the script will be changing some other values and monitoring how the responses react.
My problem is this -- it is possible that the parser could throw an exception and that renders any of the remaining script invalid. But, I can't find a good way to interrupt the script (i.e. void Main() below) should this parallel task throw. If I wait until my script is done, and then await the task, I do get the exception, but by then there is potentially a lot of time wasted. So I'm looking for better ways to interrupt the script that is running should the parallel task error. I've tried posting on the initial synchronization context but with no luck as well. I've parred down an example below to simulate a similar scenario
public class Test : TestPlugin
{
Task _t;
List<string> data = new List();
public Test(){ }
public override void Cleanup()
{
//_t.Wait();
}
public override void Main()
{
// i want this to be interrupted if the polling task started in startup throws.
//Right here simulates running test steps,
//any of which can access the data that's been updated by the "background" task at any time
try
{
int i = 0;
while (i < 10)
{
Task.Delay(1000).Wait();
Console.WriteLine("step" + i + "Latest: " + data.latest());
i++;
}
}
catch(Exception ex)
{
Console.WriteLine("EXCEPTION");
}
}
public override void Setup()
{
_t = Task.Run(async () =>
{
int i =0;
while (i < 10)
{
await Task.Delay(200);
Console.WriteLine(i);
i++;
//i would parse incoming data and add to array here
data.add(i);
if (i > 3) throw new Exception("UH OH");
}
});
}
}

You could investigate the Task.ContinueWith method on the calling task code.
this ContinueWith allows for a delegate callback that gets triggered on completion and/or exceptions. so perhaps within the ContinueWith delegate, do a check if the task completes successfully, if not then raise a new exception there appending the thrown exception passed to the delegate.
You can use the code below as an example:
Task t1 = factory.StartNew(() =>
{
DoSomething();
}).ContinueWith((t2) =>
{
if (t2.IsCanceled)
DoSomethingWhenCancelled();
else if (t2.IsFaulted)
DoSomethingOnError(t1.Exception);
else
DoSomethingWhenComplete();
});

I think I am going to have to end up with something like the following. Unfortunately this forces developers of these test procedures to need to wrap all test steps that execute in parallel to the serial port reader with a task, but maybe it's possible for me to abstract away that implementation detail into a class with an API that manages this a bit better for them.
public override void Main()
{
Task steps = Task.Run(async () =>
{
int i = 1;
//this represents step 1
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
//this represents step 2
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
//this represents step 3
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
//this represents step 4
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
});
Task.WaitAny(_t, steps);
}

Related

C# async method call with or without await call gives same result?

I have a simple program to test async/await, 2 versions: version 1 awaits another method inside async function, version doesn't:
Program 1:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("main starts..");
AsyncMethod();
Thread.Sleep(1000);
Console.WriteLine("main ends..");
Console.ReadLine();
}
static async void AsyncMethod()
{
Console.WriteLine("async starts");
var result = await MyMethod();
Console.WriteLine("async starts ends");
}
static async Task<int> MyMethod()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("async runs" + i.ToString() + "..");
await Task.Delay(1000);
}
return 0;
}
}
Program 2:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("main starts..");
AsyncMethod();
Thread.Sleep(1000);
Console.WriteLine("main ends..");
Console.ReadLine();
}
static async void AsyncMethod()
{
Console.WriteLine("async starts");
for (int i = 0; i < 5; i++)
{
Console.WriteLine("async runs" + i.ToString() + "..");
await Task.Delay(1000);
}
Console.WriteLine("async ends");
}
}
Both programs yields same result. I am just curious, do both program differs in what happens in the background?
I guess, program 1 will create 2 sub-threads, each level of "async" leads to a thread; program 2 will create 1 sub-thread. Right?
As long as "await" will wait until the task ends, then what's the difference from writing synchronous code? I think it just link creating several threads and call ".join()" for all of them. Right?
Both are async or Threaded programming using await means until your function execute your execution pointer will be hold on that functions it self and if you don't use wait it will pass on to next execution pointer mostly there is two reason behind adding await mostly in winform application while going for big process execution we may need to let software user to do the other work in the same form then we need to await the task. or some times we need get some data from one method so the method should be finished and next logic should execute in a new or other thread.

Task.Status should be Running but shows RanToCompletion

I'm puzzled with this situation, where a class has a method that launches two periodic Tasks and then a property is used to check if both Tasks are still running or not, but the result is unexpected. Here is the code (simplified):
public partial class UdpClientConnector
{
Task localListener;
Task periodicSubscriber;
bool keepWorking = false;
public bool IsRunning
{
get
{
if ((localListener != null) && (periodicSubscriber != null))
{
return (localListener.Status == TaskStatus.Running) &&
(periodicSubscriber.Status == TaskStatus.Running);
}
else
return false;
}
}
public void Start()
{
keepWorking = true;
localListener = new Task(() => LocalListenerWorker());
localListener.Start();
periodicSubscriber = new Task(() => PeriodicSubscriberWorker());
periodicSubscriber.Start();
}
public void Stop()
{
keepWorking = false;
localListener.Wait();
periodicSubscriber.Wait();
}
async void LocalListenerWorker()
{
while (keepWorking)
{
// Do some work and then wait a bit
await Task.Delay(1000);
}
}
async void PeriodicSubscriberWorker()
{
while (keepWorking)
{
// Do some (other) work and then wait a bit
await Task.Delay(1000);
}
}
}
To test this boilerplate I used the following:
UdpClientConnector connector = new UdpClientConnector();
// This assert is successful because the two Tasks are not yet started
Assert.IsTrue(!connector.IsRunning);
// Starts the tasks and wait a bit
Connector.Start();
Task.Delay(2000).Wait();
// This fails
Assert.IsTrue(connector.IsRunning);
When I've tried to debug the test case, I've found that two Tasks are in the RanToCompletion state, which is unexpected due the fact that both tasks are just loops and should not terminate until keepWorking becomes false.
I've tried also to start the Tasks using Task.Factory.StartNew(..) with same results.
What I'm missing? Thank you!
The problem is with how you start the tasks, and indeed the task methods.
localListener = new Task(() => LocalListenerWorker());
That task will complete when LocalListenerWorker returns - which it will do pretty much immediately (when it hits the first await expression). It doesn't wait for the asynchronous operation to actually complete (i.e. the loop to finish).
async void methods should almost never be used - they're basically only there to support event handlers.
I suggest you rewrite your methods to return Task, and then use Task.Run to start them, passing in a method group:
Task.Run(LocalListenerWorker);
...
private async Task LocalListenerWorker()
{
// Body as before
}
The task by Task.Run will only complete when the task returned by LocalListenerWorker completes, which is when the loop body finishes.
Here's a complete demo:
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Task task1 = Task.Run(Loop);
// Don't do this normally! It's just as a simple demo
// in a console app...
task1.Wait();
Console.WriteLine("First task done");
Task task2 = new Task(() => Broken());
task2.Start();
// Don't do this normally! It's just as a simple demo
// in a console app...
task2.Wait();
Console.WriteLine("Second task done");
}
static async Task Loop()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine(i);
}
}
static async void Broken()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine(i);
}
}
}
The output shows:
0
1
2
3
4
First task done
Second task done
The first task behaves as expected, and only completes when the first async method has really completed. The second task behaves like your current code: it completes as soon as the second async method has returned - which happens almost immediately due to the await.

Understanding async/await vs Wait in C# with "ContinueWith" behavior

One method is a standard async method, like this one :
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
I have tested two implementations, one that use await and the other uses .Wait()
The two implementations are not equal at all because the same tests are failing with the await version but not the Wait() one.
The goal of this method is to "execute a Task returned by the input function, and retry by executing the same function until it works" (with limitations to stop automatically if a certain number of tries is reached).
This works:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(t =>
{
// Wait for the recursive call to complete
AutoRetryHandlerAsync_Worker(taskToRun).Wait();
});
// Stop
return;
}
}
And this (with async t => and the usage of await instead of t => and the usage of .Wait() doesn't work at all because the result of the recursive call is not awaited before the final return; is executed :
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(async t =>
{
// Wait for the recursive call to complete
await AutoRetryHandlerAsync_Worker(taskToRun);
});
// Stop
return;
}
}
I'm trying to understand why this simple change does change everything, when it's supposed to do the exact same thing : waiting the ContinueWith completion.
If I extract the task ran by the ContinueWith method, I do see the state of the ContinueWith function passing to "ranToCompletion" before the return of the inner await completes.
Why? Isn't it supposed to be awaited?
Concrete testable behaviour
public static void Main(string[] args)
{
long o = 0;
Task.Run(async () =>
{
// #1 await
await Task.Delay(1000).ContinueWith(async t =>
{
// #2 await
await Task.Delay(1000).ContinueWith(t2 => {
o = 10;
});
});
var hello = o;
});
Task.Delay(10000).Wait();
}
Why does var hello = o; is reached before o=10?
Isn't the #1 await supposed to hang on before the execution can continue?
The lambda syntax obscures the fact that you ContinueWith(async void ...).
async void methods are not awaited and any errors they throw will go unobserved.
And to your base question, retrying from within a catch is not a recommended practice anyway. Too much going on, catch blocks should be simple. And bluntly retrying for all exception types is also very suspect. You ought to have an idea what errors could warrant a retry, and let the rest pass.
Go for simplicity and readability:
while (count++ < N)
{
try
{
MainAction();
break;
}
catch(MoreSpecificException ex) { /* Log or Ignore */ }
Delay();
}

Random tasks from Task.Factory.StartNew never finishes

I am using Async await with Task.Factory method.
public async Task<JobDto> ProcessJob(JobDto jobTask)
{
try
{
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
await T;
}
This method I am calling inside a loop like this
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
What I notice is that new tasks opens up inside Process explorer and they also start working (based on log file). however out of 10 sometimes 8 or sometimes 7 finishes. Rest of them just never come back.
why would that be happening ?
Are they timing out ? Where can I set timeout for my tasks ?
UPDATE
Basically above, I would like each Task to start running as soon as they are called and wait for the response on AWAIT T keyword. I am assuming here that once they finish each of them will come back at Await T and do the next action. I am alraedy seeing this result for 7 out of 10 tasks but 3 of them are not coming back.
Thanks
It is hard to say what the issues is without the rest if the code, but you code can be simplified by making ProcessJob synchronous and then calling Task.Run with it.
public JobDto ProcessJob(JobDto jobTask)
{
JobWorker jobWorker = new JobWorker();
return jobWorker.Execute(jobTask);
}
Start tasks and wait for all tasks to finish. Prefer using Task.Run rather than Task.Factory.StartNew as it provides more favourable defaults for pushing work to the background. See here.
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = Task.Run(() => ProcessJob(jobList[i]));
}
try
{
await Task.WhenAll(tasks);
}
catch(Exception ex)
{
// handle exception
}
First, let's make a reproducible version of your code. This is NOT the best way to achieve what you are doing, but to show you what is happening in your code!
I'll keep the code almost same as your code, except I'll use simple int rather than your JobDto and on completion of the job Execute() I'll write in a file that we can verify later. Here's the code
public class SomeMainClass
{
public void StartProcessing()
{
var jobList = Enumerable.Range(1, 10).ToArray();
var tasks = new Task[10];
//[1] start 10 jobs, one-by-one
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
//[4] here we have 10 awaitable Task in tasks
//[5] do all other unrelated operations
Thread.Sleep(1500); //assume it works for 1.5 sec
// Task.WaitAll(tasks); //[6] wait for tasks to complete
// The PROCESS IS COMPLETE here
}
public async Task ProcessJob(int jobTask)
{
try
{
//[2] start job in a ThreadPool, Background thread
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
//[3] await here will keep context of calling thread
await T; //... and release the calling thread
}
catch (Exception) { /*handle*/ }
}
}
public class JobWorker
{
static object locker = new object();
const string _file = #"C:\YourDirectory\out.txt";
public void Execute(int jobTask) //on complete, writes in file
{
Thread.Sleep(500); //let's assume does something for 0.5 sec
lock(locker)
{
File.AppendAllText(_file,
Environment.NewLine + "Writing the value-" + jobTask);
}
}
}
After running just the StartProcessing(), this is what I get in the file
Writing the value-4
Writing the value-2
Writing the value-3
Writing the value-1
Writing the value-6
Writing the value-7
Writing the value-8
Writing the value-5
So, 8/10 jobs has completed. Obviously, every time you run this, the number and order might change. But, the point is, all the jobs did not complete!
Now, if I un-comment the step [6] Task.WaitAll(tasks);, this is what I get in my file
Writing the value-2
Writing the value-3
Writing the value-4
Writing the value-1
Writing the value-5
Writing the value-7
Writing the value-8
Writing the value-6
Writing the value-9
Writing the value-10
So, all my jobs completed here!
Why the code is behaving like this, is already explained in the code-comments. The main thing to note is, your tasks run in ThreadPool based Background threads. So, if you do not wait for them, they will be killed when the MAIN process ends and the main thread exits!!
If you still don't want to await the tasks there, you can return the list of tasks from this first method and await the tasks at the very end of the process, something like this
public Task[] StartProcessing()
{
...
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
...
return tasks;
}
//in the MAIN METHOD of your application/process
var tasks = new SomeMainClass().StartProcessing();
// do all other stuffs here, and just at the end of process
Task.WaitAll(tasks);
Hope this clears all confusion.
It's possible your code is swallowing exceptions. I would add a ContineWith call to the end of the part of the code that starts the new task. Something like this untested code:
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
}).ContinueWith(tsk =>
{
var flattenedException = tsk.Exception.Flatten();
Console.Log("Exception! " + flattenedException);
return true;
});
},TaskContinuationOptions.OnlyOnFaulted); //Only call if task is faulted
Another possibility is that something in one of the tasks is timing out (like you mentioned) or deadlocking. To track down whether a timeout (or maybe deadlock) is the root cause, you could add some timeout logic (as described in this SO answer):
int timeout = 1000; //set to something much greater than the time it should take your task to complete (at least for testing)
var task = TheMethodWhichWrapsYourAsyncLogic(cancellationToken);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await task;
}
else
{
// timeout/cancellation logic
}
Check out the documentation on exception handling in the TPL on MSDN.

How to know if Task or Void method is still running when using Async

I am trying to use async and await and my problem is that it wont wait for the background process to finish. Maybe you are wondering why don't I just run the application synchronously?
I'm trying finish a part of my task ASAP and the rest can be awaited as shown in this example.
Thank you for the help guys! =)
class Program
{
static void Main(string[] args)
{
Run();
//Problem or Maybe Not? Needs this
//So that my application won't close immediately
Console.ReadLine();
}
private async static void Run()
{
Task<bool> TBool = ProcessRecords();
if (await TBool)
{
//Problem #1 This Line Doesn't Show
Console.WriteLine("End of Code");
//SHould be safe to close the application by Now
//But goes through here not waiting for the return
//of the last process.
Environment.Exit(0);
//My temporary solution is to indicate a Task.Delay(80000)
//to make sure that all the logging in the background
//are all done. I dont know if there is a function that shows
//that there are task running on the background or any
//other workaroung will help. =) thanks
}
}
private async static Task<bool> ProcessRecords()
{
Task newTask = null;
//Loop through all the records and send
//all the records to MQ ASAP
for (int x = 0; x < 10; x++)
{
//I wont wait for this Task so
//I can send the next record
newTask = SendToMQ(x);
}
//I only need to wait for the last Task to
//indicate that I can exit the system
//as soon as it finish
//Problem #2 The Console.WriteLine doesnt show the last record.
await newTask;
return true;
}
private async static Task SendToMQ(int count)
{
//actual sending of message (Important)
await Task.Delay(1000);
//Process of Logging Connect to DB etc, (Not so Important, but takes most of the time)
await LoggingRecord();
Console.Clear();
Console.WriteLine("Done Processing " + count.ToString() + " records");
}
//Logging of each record
private async static Task LoggingRecord()
{
await Task.Delay(5000);
//Problem #3 This Line Doesn't Show
Console.WriteLine("Last Log Finished");
}
}
You should use await whenever possible:
await Run();
However, in this case you cannot, so you must use Wait
static void Main(string[] args)
{
Run().Wait();
//Problem or Maybe Not? Needs this
//So that my application won't close immediately
//Console.ReadLine();
}
// note the return type is Task
private async static Task Run()
{
...
}
In ProcessRecords() you have the following line - I am not quite sure what you mean, so I didn't address it:
//Problem #2 The Console.WriteLine doesnt show the last record.
The above prints out
Done Processing 9 records
End of Code

Categories

Resources