Awaiting manually created task is freezing ASP.NET app - c#

I've made a queue, which contains tasks to do. After creating some tasks manually with new Task() in Returns method, my whole application hangs - await current;. The body of the task is not even triggered.
ConfigureAwait(false) didn't help.
The first task in the queue, which is not created by me, but other framework is executing successfully and returning a value. Mine - doesn't. I've tried add Task.CompletedTask and then it has worked. I don't understand why I can't even reach the body of the task containing _output assignment.
IDE debugger code screenshot
---UPDATE---
The code works when I use code below. With await it doesn't. Any ideas?
current.Start();
current.Wait();
Original code
private readonly Queue<Task> _pipe;
public IPipeBuilder<TOutput> Returns(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
_pipe.Enqueue(new Task(() => // this task causes a problem and breakpoint isn't hit inside
{
_output = outputBuilder(_results);
}));
return this;
}
public async Task<TOutput> Execute()
{
Task current;
while (_pipe.TryDequeue(out current))
{
if (current.IsCommandExecution())
{
IExecutionResult result = await (Task<IExecutionResult>)current; // this awaits successfully
_results.Add(result);
}
else
{
await current; // hangs here
}
}
return await Task.FromResult(_output);
}
Usage
[HttpGet("eventflow/pipe/issue/add/{title}")]
public async Task<IActionResult> PipeAction(string title)
=> Ok(
await Pipe<IExecutionResult>()
.Validate(title)
.Handle<AddIssueCommand>(IssueId.New, title)
.Returns(results => results.First())
.Execute());

You should never use the Task constructor. This goes double on ASP.NET, since constructed tasks are always Delegate Tasks, which interfere with the ASP.NET usage of the thread pool. The actual reason that the await hangs is because manually-created tasks need to be started.
If you have synchronous work that you need to wrap into a Task to work alongside asynchronous tasks, then you should use Task.CompletedTask and Task.FromException:
private static Task SynchronousWork(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
try { _output = outputBuilder(_results); return Task.CompletedTask; }
catch (Exception ex) { return Task.FromException(ex); }
}
public IPipeBuilder<TOutput> Returns(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
_pipe.Enqueue(SynchronousWork(outputBuilder));
return this;
}
However, note that this executes outputBuilder immediately, which may not be desirable due to its side effects on _results and _output. If you want a delayed execution queue, then the type in the queue needs to be changed from Task to Func<Task>. Then you can add to it as such:
public IPipeBuilder<TOutput> Returns(Func<IEnumerable<IExecutionResult>, TOutput> outputBuilder)
{
_pipe.Enqueue(() =>
{
try { _output = outputBuilder(_results); return Task.CompletedTask; }
catch (Exception ex) { return Task.FromException(ex); }
});
return this;
}
and you would consume it by calling each delegate one at a time and inspecting the task it returns:
public async Task<TOutput> Execute()
{
while (_pipe.TryDequeue(out var currentFunc))
{
var currentTask = currentFunc();
if (currentTask.IsCommandExecution())
{
IExecutionResult result = await (Task<IExecutionResult>)currentTask;
_results.Add(result);
}
else
{
await currentTask;
}
}
return _output;
}

Okay, thank you. I've ended up with such class and Queue<Func<Task>> like you said.
public sealed class SyncTaskWrapper
{
private Func<Task> _action;
public SyncTaskWrapper(Action action)
=> _action = CreateFunc(action);
private static Func<Task> CreateFunc(Action action)
=> () =>
{
try
{
action();
return Task.CompletedTask;
}
catch (Exception exception)
{
return Task.FromException(exception);
}
};
public static implicit operator Func<Task>(SyncTaskWrapper #this)
=> #this._action;
}
with usage
_pipe.Enqueue(new SyncTaskWrapper(() =>
_output = outputBuilder(_results)));

Related

.NET Client-Side WCF w/Queued Tasks

In modernizing, I'm trying to update legacy libraries to use a client-side WCF service. The following is close to what I need, but I can't figure out how to add the created task to a queue that will only process one request at a time.
[ServiceContract(Name="MyService", SessionMode=Session.Required]
public interface IMyServiceContract
{
[OperationContract()]
Task<string> ExecuteRequestAsync(Action action);
}
public class MyService: IMyServiceContract
{
// How do I get this piece in a task queue?
public async Task<string> ExecuteRequestAsync(Request request)
{
return await Task.Factory.StartNew(() => request.Execute();)
}
}
I've looked at TaskQueue's that Servy shared (Best way in .NET to manage queue of tasks on a separate (single) thread). But, I'm having trouble combining the two into something that works. When I attempt to add my task to the TaskQueue below, the task never runs. I know I'm missing something, so any help is greatly appreciated.
public class TaskQueue
{
private SemaphoreSlim semaphore;
public TaskQueue()
{
semaphore = new SemaphoreSlim(1);
}
public async Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
{
await semaphore.WaitAsync();
try
{
return await taskGenerator();
}
finally
{
semaphore.Release();
}
}
public async Task Enqueue(Func<Task> taskGenerator)
{
await semaphore.WaitAsync();
try
{
await taskGenerator();
}
finally
{
semaphore.Release();
}
}
}
Thanks
I ended up adding to the TaskQueue:
Task<T> Enqueue<T>(Func<T> function)
{
await semaphore.WaitAsync();
try
{
return await Task.Factory.StartNew(() => function.invoke();)
}
finally
{
semaphore.Release();
}
}
And, update the host to the following:
return await queue.Enqueue(request.Execute();)
And, this is doing what I need from the WCF service. The items execute FIFO from multiple applications sending requests.

await a Task and silently stop on cancel or failure

What I would like to write is the following:
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
Instead of:
void Foo()
{
GetMyTask().ContinueWith(task => ProcessResult(task.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
However I don't know how to implement the method IgnoreCancelAndFailure, which would have the following signature:
//On cancel or failure this task should simply stop and never complete.
Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
throw new NotImplementedException();
}
If possible, how should I implement IgnoreCancelAndFailure?
You could do something like that, but you need to know what you want the method to return in case of failure, since a return value is expected:
public static async Task<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
try
{
return await task;
}
catch
{
return ???; // whatever you want to return in this case
}
}
If it's a Task with no result, just leave the catch empty (or perhaps log the exception... swallowed exceptions make for hard debugging)
If you just want to execute ProcessResult only when GetMyTask succeeds, you can do this:
async void Foo()
{
try
{
var result = await GetMyTask();
ProcessResult(result);
}
catch(Exception ex)
{
// handle the exception somehow, or ignore it (not recommended)
}
}
You will never be able to stop your code from continuing expect when killing the thread or process. keep in mind that the await task can be considered a function call that will always have to return a value or throw an exception.
The closest way to shorten your code is creating a wrapper function that uses the ProcessResult method as Action argument.
Something like that:
public static async Task IgnoreCancelAndFailure<T>(this Task<T> task, Action<T> resultProcessor)
{
task.ContinueWith(t => resultProcessor(t.Result),
TaskContinuationOptions.OnlyOnRanToCompletion);
}
async void Foo()
{
GetMyTask().IgnoreCancelAndFailure(ProcessResult);
}
I think I found the answer. The following seems to do the trick. It uses the awaitable pattern. Could you guys confirm that this isn't evil?
class User
{
async void Foo()
{
var result = await GetMyTask().IgnoreCancelAndFailure();
ProcessResult(result);
}
}
public static class TaskExtenstions
{
public static SilentTask<T> IgnoreCancelAndFailure<T>(this Task<T> task)
{
return new SilentTask<T>(task);
}
}
public class SilentTask<T>
{
private readonly Task<T> _inner;
public SilentTask(Task<T> inner)
{
_inner = inner;
}
public SilentAwaiter GetAwaiter()
{
return new SilentAwaiter(_inner);
}
public class SilentAwaiter : INotifyCompletion
{
private readonly TaskAwaiter<T> _inner;
private readonly Task<T> _task;
public SilentAwaiter(Task<T> task)
{
_task = task;
_inner = task.GetAwaiter();
}
public bool IsCompleted
{
get
{
return _task.Status == TaskStatus.RanToCompletion;
}
}
public void OnCompleted(Action continuation)
{
_inner.OnCompleted(() =>
{
if (IsCompleted)
{
continuation();
}
});
}
public T GetResult()
{
return _inner.GetResult();
}
}
}

await not blocking until Task finishes

I am trying to block RequestHandler.ParseAll() with await ConsumerTask;, but when i set a breakpoint there, i ALWAYS get the "Done..." output first... and then Parse2() fails with a NullReferenceException. (thats my guess: "the GC starts cleaning up because _handler got out of scope")
Anyway, I can't figure out why that happens.
class MainClass
{
public async void DoWork()
{
RequestHandler _handler = new RequestHandler();
string[] mUrls;
/* fill mUrls here with values */
await Task.Run(() => _handler.ParseSpecific(mUrls));
Console.WriteLine("Done...");
}
}
static class Parser
{
public static async Task<IEnumerable<string>> QueryWebPage(string url) { /*Query the url*/ }
public static async Task Parse1(Query query)
{
Parallel.ForEach(/*Process data here*/);
}
public static async Task Parse2(Query query)
{
foreach(string line in query.WebPage)
/* Here i get a NullReference exception because query.WebPage == null */
}
}
sealed class RequestHandler
{
private BlockingCollection<Query> Queue;
private Task ConsumerTask = Task.Run(() => /* call consume() for each elem in the queue*/);
private async void Consume(Query obj)
{
await (obj.BoolField ? Parser.Parse1(obj) : Parser.Parse2(obj));
}
public async void ParseSpecific(string[] urls)
{
foreach(string v in urls)
Queue.Add(new Query(await QueryWebPage(v), BoolField: false));
Queue.CompleteAdding();
await ConsumerTask;
await ParseAll(true);
}
private async Task ParseAll(bool onlySome)
{
ReInit();
Parallel.ForEach(mCollection, v => Queue.Add(new Query(url, BoolField:false)));
Queue.CompleteAdding();
await ConsumerTask;
/* Process stuff further */
}
}
struct Query
{
public readonly string[] WebPage;
public readonly bool BoolField;
public Query(uint e, IEnumerable<string> page, bool b) : this()
{
Webpage = page.ToArray();
BoolField = b;
}
}
CodesInChaos has spotted the problem in comments. It stems from having async methods returning void, which you should almost never do - it means you've got no way to track them.
Instead, if your async methods don't have any actual value to return, you should just make them return Task.
What's happening is that ParseSpecific is only running synchronously until the first await QueryWebPage(v) that doesn't complete immediately. It's then returning... so the task started here:
await Task.Run(() => _handler.ParseSpecific(mUrls));
... completes immediately, and "Done" gets printed.
Once you've made all your async methods return Task, you can await them. You also won't need Task.Run at all. So you'd have:
public async void DoWork()
{
RequestHandler _handler = new RequestHandler();
string[] mUrls;
await _handler.ParseSpecific(mUrls);
Console.WriteLine("Done...");
}
...
public async TaskParseSpecific(string[] urls)
{
foreach(string v in urls)
{
// Refactored for readability, although I'm not sure it really
// makes sense now that it's clearer! Are you sure this is what
// you want?
var page = await QueryWebPage(v);
Queue.Add(new Query(page, false);
}
Queue.CompleteAdding();
await ConsumerTask;
await ParseAll(true);
}
Your Reinit method also needs changing, as currently the ConsumerTask will basically complete almost immediately, as Consume will return immediately as it's another async method returning void.
To be honest, what you've got looks very complex, without a proper understanding of async/await. I would read up more on async/await and then probably start from scratch. I strongly suspect you can make this much, much simpler. You might also want to read up on TPL Dataflow which is designed to make producer/consumer scenarios simpler.

Deadlock when combining app domain remoting and tasks

My app needs to load plugins into separate app domains and then execute some code inside of them asynchronously. I've written some code to wrap Task in marshallable types:
static class RemoteTask
{
public static async Task<T> ClientComplete<T>(RemoteTask<T> remoteTask,
CancellationToken cancellationToken)
{
T result;
using (cancellationToken.Register(remoteTask.Cancel))
{
RemoteTaskCompletionSource<T> tcs = new RemoteTaskCompletionSource<T>();
remoteTask.Complete(tcs);
result = await tcs.Task;
}
await Task.Yield(); // HACK!!
return result;
}
public static RemoteTask<T> ServerStart<T>(Func<CancellationToken, Task<T>> func)
{
return new RemoteTask<T>(func);
}
}
class RemoteTask<T> : MarshalByRefObject
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly Task<T> task;
internal RemoteTask(Func<CancellationToken, Task<T>> starter)
{
this.task = starter(cts.Token);
}
internal void Complete(RemoteTaskCompletionSource<T> tcs)
{
task.ContinueWith(t =>
{
if (t.IsFaulted)
{
tcs.TrySetException(t.Exception);
}
else if (t.IsCanceled)
{
tcs.TrySetCancelled();
}
else
{
tcs.TrySetResult(t.Result);
}
}, TaskContinuationOptions.ExecuteSynchronously);
}
internal void Cancel()
{
cts.Cancel();
}
}
class RemoteTaskCompletionSource<T> : MarshalByRefObject
{
readonly TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
public bool TrySetResult(T result) { return tcs.TrySetResult(result); }
public bool TrySetCancelled() { return tcs.TrySetCanceled(); }
public bool TrySetException(Exception ex) { return tcs.TrySetException(ex); }
public Task<T> Task
{
get
{
return tcs.Task;
}
}
}
It's used like:
sealed class ControllerAppDomain
{
PluginAppDomain plugin;
public Task<int> SomethingAsync()
{
return RemoteTask.ClientComplete(plugin.SomethingAsync(), CancellationToken.None);
}
}
sealed class PluginAppDomain : MarshalByRefObject
{
public RemoteTask<int> SomethingAsync()
{
return RemoteTask.ServerStart(async cts =>
{
cts.ThrowIfCancellationRequested();
return 1;
});
}
}
But I've run into a snag. If you look in ClientComplete, there's a Task.Yield() I've inserted. If I comment this line, ClientComplete will never return. Any ideas?
My best guess is that you are facing these issues because of the async method that contains await and this is managed via the ThreadPool which can allocate some recycled Thread.
Reference
Best practice to call ConfigureAwait for all server-side code
Actually, just doing an await can do that(put you on a different thread). Once your async method hits
an await, the method is blocked but the thread returns to the thread
pool. When the method is ready to continue, any thread is snatched
from the thread pool and used to resume the method.
Try to streamline the code, generate threads for baseline cases and
performance is last.

TPL Queue Processing

I'm currently working on a a project and I have a need to queue some jobs for processing, here's the requirement:
Jobs must be processed one at a time
A queued item must be able to be waited on
So I want something akin to:
Task<result> QueueJob(params here)
{
/// Queue the job and somehow return a waitable task that will wait until the queued job has been executed and return the result.
}
I've tried having a background running task that just pulls items off a queue and processes the job, but the difficulty is getting from a background task to the method.
If need be I could go the route of just requesting a completion callback in the QueueJob method, but it'd be great if I could get a transparent Task back that allows you to wait on the job to be processed (even if there are jobs before it in the queue).
You might find TaskCompletionSource<T> useful, it can be used to create a Task that completes exactly when you want it to. If you combine it with BlockingCollection<T>, you will get your queue:
class JobProcessor<TInput, TOutput> : IDisposable
{
private readonly Func<TInput, TOutput> m_transform;
// or a custom type instead of Tuple
private readonly
BlockingCollection<Tuple<TInput, TaskCompletionSource<TOutput>>>
m_queue =
new BlockingCollection<Tuple<TInput, TaskCompletionSource<TOutput>>>();
public JobProcessor(Func<TInput, TOutput> transform)
{
m_transform = transform;
Task.Factory.StartNew(ProcessQueue, TaskCreationOptions.LongRunning);
}
private void ProcessQueue()
{
Tuple<TInput, TaskCompletionSource<TOutput>> tuple;
while (m_queue.TryTake(out tuple, Timeout.Infinite))
{
var input = tuple.Item1;
var tcs = tuple.Item2;
try
{
tcs.SetResult(m_transform(input));
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
}
public Task<TOutput> QueueJob(TInput input)
{
var tcs = new TaskCompletionSource<TOutput>();
m_queue.Add(Tuple.Create(input, tcs));
return tcs.Task;
}
public void Dispose()
{
m_queue.CompleteAdding();
}
}
I would go for something like this:
class TaskProcessor<TResult>
{
// TODO: Error handling!
readonly BlockingCollection<Task<TResult>> blockingCollection = new BlockingCollection<Task<TResult>>(new ConcurrentQueue<Task<TResult>>());
public Task<TResult> AddTask(Func<TResult> work)
{
var task = new Task<TResult>(work);
blockingCollection.Add(task);
return task; // give the task back to the caller so they can wait on it
}
public void CompleteAddingTasks()
{
blockingCollection.CompleteAdding();
}
public TaskProcessor()
{
ProcessQueue();
}
void ProcessQueue()
{
Task<TResult> task;
while (blockingCollection.TryTake(out task))
{
task.Start();
task.Wait(); // ensure this task finishes before we start a new one...
}
}
}
Depending on the type of app that is using it, you could switch out the BlockingCollection/ConcurrentQueue for something simpler (eg just a plain queue). You can also adjust the signature of the "AddTask" method depending on what sort of methods/parameters you will be queueing up...
Func<T> takes no parameters and returns a value of type T. The jobs are run one by one and you can wait on the returned task to get the result.
public class TaskQueue
{
private Queue<Task> InnerTaskQueue;
private bool IsJobRunning;
public void Start()
{
Task.Factory.StartNew(() =>
{
while (true)
{
if (InnerTaskQueue.Count > 0 && !IsJobRunning)
{
var task = InnerTaskQueue.Dequeue()
task.Start();
IsJobRunning = true;
task.ContinueWith(t => IsJobRunning = false);
}
else
{
Thread.Sleep(1000);
}
}
}
}
public Task<T> QueueJob(Func<T> job)
{
var task = new Task<T>(() => job());
InnerTaskQueue.Enqueue(task);
return task;
}
}

Categories