I have a unit test which is running forever:
[Test]
public bool test()
{
manager.Send(10);
Thread.Sleep(1000);
manager.Messages.Should().HaveCount(10);
return true;
}
manager.Send() method is:
private void Send()
{
try
{
var entities = GetAllEntities();
foreach (var group in entities.GroupBy(r => r.Priority))
{
var tasks = group.Select(entity => Task.Factory.StartNew(() => manager.SendEntity(entity))).ToList();
Task.WaitAll(tasks.ToArray());
if (tasks.All(r => r.Result.Result == true))
{
// some code here...
}
}
}
catch (Exception e)
{
logger.FatalException(e.Message, e);
}
finally
{
logger.Info("End...");
}
}
and SendEntity() method:
public Task<bool> SendEntity(DeferredEntity entity)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
try
{
logger.Info("Sending entity {0} with params: {1}", entity.Entity, GetEntityParams(entity));
server.SendToServer(entity, (response, result) =>
{
taskCompletionSource.SetResult(result);
});
}
catch (Exception e)
{
logger.FatalException(e.Message, e);
}
return taskCompletionSource.Task;
}
in unit test manager.Send(10) is running forever. I debuged the code and I see that the problem is in
if (tasks.All(r => r.Result.Result == true))
the debugger stops on this line and sleeps forever. What I am doing wrong? I added return value of unit test method to bool (async methods doesn't throw exceptions in void methods). But it doesn't help. Do you have any suggestions?
You get the deadlock there.
First of all you don't have to start the new Thread with
Task.Factory.StartNew(() => manager.SendEntity(entity)
It seems SendToServer is already async.
It also a bad practice to use the Task.Wait***/Task.Result, use the async flow
private async Task Send()
{
try
{
var entities = GetAllEntities();
foreach (var group in entities.GroupBy(r => r.Priority))
{
var tasks = group
.Select(entity => manager.SendEntity(entity))
.ToArray();
var results = await Task.WhenAll(tasks);
if (results.All(result => result))
{
// some code here...
}
}
}
catch (Exception e)
{
logger.FatalException(e.Message, e);
}
finally
{
logger.Info("End...");
}
}
But if you don't want to rewrite the Send Method you can use .ConfigureAwait(false)
return taskCompletionSource.Task.ConfigureAwait(false);
But anyway, remove the StartNew - you don't need this.
Related
Is there any way to convert the Task to a Task async or something similar?
I'm testing code, in short learning to perform different functions of Task type and learn to use its correct operation, however I have not been able to solve this "problem", so I want to ask people who have more knowledge about the Tasks.
Task<bool>.Factory.StartNew(() => {}); -> Task<bool>.Factory.StartNew(async () => {});
Here is a summary of what I want to do
private bool completed = false;
void Tester()
{
completed = false;
int iteration = 0;
var log = new Logger();
log.Log(Logger.Level.Debug, "Starting");
try
{
var theTask = Task<bool>.Factory.StartNew( () =>
{
while (!completed)
{
log.Log(Logger.Level.Debug, "Waiting",1);
iteration++;
Thread.Sleep(400);
if (iteration>20)
{
completed = true;
return true;
}
}
return false;
}).Result;
}
catch (Exception e)
{
log.Log(Logger.Level.Error, e.ToString());
}
finally
{
log.Log(Logger.Level.Info, "Completed");
}
}
You can do it. You can see this video to understand async/await pattern: https://www.youtube.com/watch?v=il9gl8MH17s.
Try this:
class Program
{
static async Task Main(string[] args)
{
bool result = await Tester();
System.Diagnostics.Debug.WriteLine($"result: {result}");
}
private static bool completed = false;
static async Task<bool> Tester()
{
completed = false;
int iteration = 0;
//var log = new Logger();
//log.Log(Logger.Level.Debug, "Starting");
try
{
await Task.Factory.StartNew(() =>
{
while (!completed)
{
//log.Log(Logger.Level.Debug, "Waiting", 1);
iteration++;
System.Diagnostics.Debug.WriteLine($"iteration {iteration}");
Task.Delay(2000);
if (iteration > 20)
{
completed = true;
}
}
});
}
catch (Exception e)
{
//log.Log(Logger.Level.Error, e.ToString());
}
finally
{
//log.Log(Logger.Level.Info, "Completed");
}
return completed;
}
}
In a console application I'm starting from a list and open multiple tasks to handle them like:
List<Task> tasks = new List<Task>();
tasks.Add(Task.Run(() => { Elabor(el.Take(1000).ToList(), listLogDequeues); }));
tasks.Add(Task.Run(() => { Elabor(el.Skip(1000).Take(1000).ToList(), listLogDequeues); }));
tasks.Add(Task.Run(() => { Elabor(el.Skip(2000).Take(1000).ToList(), listLogDequeues); }));
Task.WaitAll(tasks.ToArray());
el and ListLogDequeue is a ConcurrentBag<T> and inside the function an integer is incremented safely using Interlocked.Add.
This allow me to run three/four tasks and perform operations, but inside Elabor is used Entity Framework and MongoClient, as two repos injected with Ninject in my console application Main. Each function build and use it's context, but I don't get if and how concurrency and thread safety can hurt here.
EF:
public OutAnag GetAnagById(string id)
{
try
{
using (var c = new Context())
{
return c.Anag.AsNoTracking().FirstOrDefault(e => e.Id == id);
}
}
catch (Exception ex)
{
return null;
}
}
Mongo:
public bool SetElab(string guid)
{
Context dbContext = new Context();
try
{
var filter = Builders<Anag>.Filter.Where(m => m.Guid == guid);
var update = Builders<Anag>.Update.Set(m => m.DataElaborazione, DateTime.Now);
var options = new FindOneAndUpdateOptions<Anag>();
dbContext.Anag.FindOneAndUpdate(filter, update, options);
}
catch (Exception e)
{
return false;
}
return true;
}
I am working on a Task parallel problem that I have many Tasks that may or may not throw Exception.
I want to process all the tasks that finishes properly and log the rest. The Task.WhenAll propage the Task exception without allowing me to gather the rest results.
static readonly Task<string> NormalTask1 = Task.FromResult("Task result 1");
static readonly Task<string> NormalTask2 = Task.FromResult("Task result 2");
static readonly Task<string> ExceptionTk = Task.FromException<string>(new Exception("Bad Task"));
var results = await Task.WhenAll(new []{ NormalTask1,NormalTask2,ExceptionTk});
The Task.WhenAll with throw the Exception of ExcceptionTk ignoring the rest results. How I can get the results ignoring the Exception and log the exception at same time?
I could wrap the task into another task that try{...}catch(){...} the internal exception but I don't have access to them and I hope I will not have to add this overhead.
You can create a method like this to use instead of Task.WhenAll:
public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{
return Task.WhenAll(
tasks.Select(
task => task.ContinueWith(
t => t.IsFaulted
? new ResultOrException<T>(t.Exception)
: new ResultOrException<T>(t.Result))));
}
public class ResultOrException<T>
{
public ResultOrException(T result)
{
IsSuccess = true;
Result = result;
}
public ResultOrException(Exception ex)
{
IsSuccess = false;
Exception = ex;
}
public bool IsSuccess { get; }
public T Result { get; }
public Exception Exception { get; }
}
Then you can check each result to see if it was successful or not.
EDIT: the code above doesn't handle cancellation; here's an alternative implementation:
public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{
return Task.WhenAll(tasks.Select(task => WrapResultOrException(task)));
}
private async Task<ResultOrException<T>> WrapResultOrException<T>(Task<T> task)
{
try
{
var result = await task;
return new ResultOrException<T>(result);
}
catch (Exception ex)
{
return new ResultOrException<T>(ex);
}
}
You can get the result of each successfully completed Task<TResult> from its property Result.
var normalTask1 = Task.FromResult("Task result 1");
var normalTask2 = Task.FromResult("Task result 2");
var exceptionTk = Task.FromException<string>(new Exception("Bad Task"));
Task<string>[] tasks = new[] { normalTask1, normalTask2, exceptionTk };
Task whenAll = Task.WhenAll(tasks);
try
{
await whenAll;
}
catch
{
if (whenAll.IsFaulted) // There is also the possibility of being canceled
{
foreach (var ex in whenAll.Exception.InnerExceptions)
{
Console.WriteLine(ex); // Log each exception
}
}
}
string[] results = tasks
.Where(t => t.IsCompletedSuccessfully)
.Select(t => t.Result)
.ToArray();
Console.WriteLine($"Results: {String.Join(", ", results)}");
Output:
System.Exception: Bad Task
Results: Task result 1, Task result 2
You can add HOC with exception handling and then check success.
class Program
{
static async Task Main(string[] args)
{
var itemsToProcess = new[] { "one", "two" };
var results = itemsToProcess.ToDictionary(x => x, async (item) =>
{
try
{
var result = await DoAsync();
return ((Exception)null, result);
}
catch (Exception ex)
{
return (ex, (object)null);
}
});
await Task.WhenAll(results.Values);
foreach(var item in results)
{
Console.WriteLine(item.Key + (await item.Value).Item1 != null ? " Failed" : "Succeed");
}
}
public static async Task<object> DoAsync()
{
await Task.Delay(10);
throw new InvalidOperationException();
}
}
My function has three parts.
Part one Parameter Popup
Part two Executes the code in a new thread with ApartmentState.STA turned on.
Part three - Show ReportViewer
I am currently receiving this error the calling thread cannot access this object because a different thread owns it.
public async void AnticipatedEntriesReport(bool fund)
{
var anticipatedReport = new AnticipatedReport(fund);
ReportPreviewForm report = new ReportPreviewForm();
anticipatedReport.InitializeParameters();
if (anticipatedReport.GetParameters() != null)
{
await RunAsyncTask(
() =>
{
report = anticipatedReport.GenerateReport(SelectedLoans);
});
report.Show();
}
}
My code breaks at report.Show().
anticipatedReport.GenerateReport returns a ReportPreviewForm.
I'm wondering what am I doing wrong? I think it's based on where I created the object.
public async Task RunAsyncTask(System.Action action)
{
try
{
await ThreadManager.StartSTATask(action);
}
catch (Exception ex)
{
}
}
public static Task StartSTATask(System.Action func)
{
var tcs = new TaskCompletionSource<object>();
var thread = new Thread(() =>
{
try
{
func();
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
Just create the report inside the task and return it to task's parent:
public async Task AnticipatedEntriesReport(bool fund)
{
var anticipatedReport = new AnticipatedReport(fund);
ReportPreviewForm report = null;
anticipatedReport.InitializeParameters();
if (anticipatedReport.GetParameters() != null)
{
// Generate the report inside the task and return it.
report = await RunAsyncTask(
() =>
{
var result = anticipatedReport.GenerateReport(SelectedLoans);
return result;
});
}
}
and in RunAsyncTask:
public async Task<TResult> RunAsyncTask<TResult>(Func<TResult> function)
{
TResult result = default(TResult);
UpdateBusyUi(true);
try
{
result = await ThreadManager.StartSTATask(function);
}
catch (Exception ex)
{
SendException(ex);
LoadSucceed = false;
Events.PublishOnUIThread(new BackgroundCompletedEvent { Header = BackgroundCompletedEvent.EntityActions.Error, Error = true });
}
UpdateBusyUi(false);
return result;
}
The StartSTATask:
Task<TResult> StartSTATask<TResult>(Func<TResult> function)
{
TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>();
Thread thread = new Thread(() =>
{
try
{
source.SetResult(function());
}
catch (Exception ex)
{
source.SetException(ex);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return source.Task;
}
Given an implementation as follows:
public class SomeServiceWrapper
{
public string GetSomeString()
{
try
{
//Do Something
}
catch (IOException e)
{
throw new ServiceWrapperException("Some Context", e);
}
catch (WebException e)
{
throw new ServiceWrapperException("Some Context", e);
}
}
}
The intention of the above is to enable the consumer of GetSomeString to only need to catch ServiceWrapperException.
Consider the following approach to extending this with a similar async behaviour:
public Task<string> GetSomeStringAsync()
{
Task<string>.Factory doSomething = ...
return doSomething.ContinueWith(x =>
{
if (x.IsFaulted)
{
if (x.Exception.InnerExceptions.Count() > 1)
{
throw new AggregateException(x.Exception);
}
var firstException = x.Exception.InnerExceptions[0];
if (typeof(firstException) == typeof(IOException)
|| typeof(firstException) == typeof(WebException))
{
throw new ServiceWrapperException("Some Context", firstException);
}
}
return x.Result;
}
}
This synchronous approach to wrapping exceptions doesn't fit naturally with the asynchronous approach.
What could the author of SomeServiceWrapper do to simplify the exception handling code of any consumers so they only need to handle TradeLoaderException instead of both IOException and WebException?
I made an extension method that pretty much does that. Usage:
public static Task<string> GetSomeStringAsync()
{
var doSomething = Task.Factory.StartNew(() => "bar");
return doSomething.WrapExceptions(typeof(IOException), typeof(WebException));
}
You can just return the original task with the continuation.
I would suggest changing ServiceWrapperException to hold more than one exception like AggregateException and then change the first part.
The Method:
public static Task<TResult> WrapExceptions<TResult>(this Task<TResult> task, params Type[] exceptionTypes)
{
return task.ContinueWith(_ =>
{
if (_.Status == TaskStatus.RanToCompletion) return _.Result;
if (_.Exception.InnerExceptions.Count > 1)
{
throw new AggregateException(_.Exception);
}
var innerException = _.Exception.InnerExceptions[0];
if (exceptionTypes.Contains(innerException.GetType()))
{
throw new ServiceWrapperException("Some Context", innerException);
}
throw _.Exception;
});
}