Why continuation executes asynchronously? - asynchronous

The code sample below
public static void Test()
{
TaskCompletionSource<bool> inner = new TaskCompletionSource<bool>();
TaskCompletionSource<bool> outer = new TaskCompletionSource<bool>();
TaskScheduler ctScheduler = new CurrentThreadTaskScheduler();
outer.Task.ContinueWith(
completedTask =>
{
Console.WriteLine("Continuation of the outer in the thread #{0}", Thread.CurrentThread.ManagedThreadId);
inner.SetResult(true);
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
Task t = Task.Run(
async () =>
{
await inner.Task;
Console.WriteLine("Awaiter continuation in the thread #{0}", Thread.CurrentThread.ManagedThreadId);
});
Thread.Sleep(1000);
Console.WriteLine("Setting the outer to completed in the thread #{0}", Thread.CurrentThread.ManagedThreadId);
outer.SetResult(true);
}
produces the following output
Setting the outer to completed in the thread #1
Continuation of the outer in the thread #4
Awaiter continuation in the thread #4
As expected, the continuation after await inner.Task was executed synchronously on the thread which completed the task, namely the thread #4.
When I'm trying to run all the continuations synchronously on the same current thread
outer.Task.ContinueWith(
completedTask =>
{
Console.WriteLine("Continuation of the outer in the thread #{0}", Thread.CurrentThread.ManagedThreadId);
inner.SetResult(true);
},
CancellationToken.None,
TaskContinuationOptions.None,
ctScheduler);
using a simple custom task scheduler, implemented as follows
public sealed class CurrentThreadTaskScheduler : TaskScheduler
{
protected override IEnumerable<Task> GetScheduledTasks()
{
return Enumerable.Empty<Task>();
}
protected override void QueueTask(Task task)
{
this.TryExecuteTask(task);
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return this.TryExecuteTask(task);
}
}
the 'awaiter' continuation runs asynchronously, as seen in the output down here
Setting the outer to completed in the thread #1
Continuation of the outer in the thread #1
Awaiter continuation in the thread #4
Why the continuation in question is running asynchronously and how should I implement the scheduler to guarantee the expected behaviour?

Related

Lazy CosmosDB Initialization takes longer when more tasks are waiting for it

Context
We have a service that is dependent on CosmosDB. We created a class, having a lazy container, that will be initialized on startup. In the startup class we do :
CreateDatabaseIfNotExist
CreateContainerIfNotExistsAsync
Problem
The first request to CosmosDB starts the initialization.
When we have multiple threads starting up before the initialization, waiting for this lazy intialization to finish, the intialization takes longer the more threads are waiting for it.
Expected
When multiple threads starting up, the threads that need to have this initialized container, should not impact the initialization duration, since this is in a locked context (lazy)
In the code example below, when changing the amount of threads to 5, the initialization is in a couple of seconds. the higher the count of threads, the higher the duration of the initialization.
code example:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos;
namespace LazyCosmos.Anon
{
class Program
{
static void Main(string[] args)
{
new Do().Run().GetAwaiter().GetResult();
}
public class Do
{
private Lazy<Container> lazyContainer;
private Container Container => lazyContainer.Value;
public Do()
{
lazyContainer = new Lazy<Container>(() => InitializeContainer().GetAwaiter().GetResult());
}
public async Task Run()
{
try
{
var tasks = new Task[100];
for (int i = 0; i < 100; i++)
{
tasks[i] = Task.Run(() =>
ReadItemAsync<Item>("XXX", "XXX"));
}
await Task.WhenAll(tasks);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public async Task<T> ReadItemAsync<T>(string id, string partitionKey)
{
var itemResponse = await Container.ReadItemAsync<T>(id, new PartitionKey(partitionKey));
return itemResponse.Resource;
}
private async Task<Container> InitializeContainer()
{
var s = Stopwatch.StartNew();
Console.WriteLine($"Started {s.ElapsedMilliseconds}s");
var configuration = new CosmosDbServiceConfiguration("XXX", null, collectionId: "XXX",
"XXX", 400);
var _cosmosClient = new ColdStorageCosmosClient(new ActorColdStorageConfiguration("XXX", "XXX", "https://XXX.XX", "XXX"));
var database = await _cosmosClient
.CreateDatabaseIfNotExistsAsync(configuration.DatabaseId, configuration.DatabaseThroughput);
Console.WriteLine($"CreateDatabaseIfNotExistsAsync took {s.ElapsedMilliseconds}s");
var containerProperties = new ContainerProperties
{
Id = configuration.ContainerId,
PartitionKeyPath = $"/{configuration.PartitionKey}",
DefaultTimeToLive = configuration.DefaultTimeToLive
};
var db = (Database)database;
var containerIfNotExistsAsync = await db.CreateContainerIfNotExistsAsync(containerProperties, configuration.ContainerThroughput);
s.Stop();
Console.WriteLine($"CreateContainerIfNotExistsAsync took {s.ElapsedMilliseconds}s");
return containerIfNotExistsAsync;
}
}
}
public class CosmosDbServiceConfiguration
{
public CosmosDbServiceConfiguration(string databaseId, int? databaseThroughput, string collectionId, string partitionKey, int? containerThroughput = null)
{
DatabaseId = databaseId;
ContainerId = collectionId;
DatabaseThroughput = databaseThroughput;
ContainerThroughput = containerThroughput;
PartitionKey = partitionKey;
}
public string DatabaseId { get; }
public int? DatabaseThroughput { get; }
public string ContainerId { get; }
public int? ContainerThroughput { get; }
public string PartitionKey { get; }
public int? DefaultTimeToLive { get; set; }
}
public class ColdStorageCosmosClient : CosmosClient
{
public ColdStorageCosmosClient(ActorColdStorageConfiguration actorColdStorageConfiguration) : base(actorColdStorageConfiguration.EndpointUrl, actorColdStorageConfiguration.Key)
{
}
}
public class ActorColdStorageConfiguration
{
public ActorColdStorageConfiguration(string databaseName, string collectionName, string endpointUrl, string key)
{
DatabaseName = databaseName;
CollectionName = collectionName;
EndpointUrl = endpointUrl;
Key = key;
}
public string DatabaseName { get; }
public string CollectionName { get; }
public string EndpointUrl { get; }
public string Key { get; }
}
public class Item
{
public string id { get; set; }
}
}
You're experiencing thread pool exhaustion. There's a few different concepts that are conflicting to cause the exhaustion.
First, even though asynchronous code does not use a thread for the duration of the asynchronous operation, it often does need to very briefly borrow a thread pool thread in order to do housework when the asynchronous operation completes. As a result, most asynchronous code only runs efficiently if there is a free thread pool thread available, and if there are no thread pool threads available, then asynchronous code may be delayed.
Another part of the puzzle is that the thread pool has a limited thread injection rate. This is deliberate, so that the thread pool isn't constantly creating/destroying threads as its load varies. That would be very inefficient. Instead, a thread pool that has all of its threads busy (and still has more work to do) will only add a thread every few seconds.
The final concept to recognize is that Lazy<T> is blocking when using the default LazyThreadSafetyMode.ExecutionAndPublication behavior. The way this Lazy<T> works is that only one thread executes the delegate (() => InitializeContainer().GetAwaiter().GetResult()). All other threads block, waiting for that delegate to complete.
So now, putting it all together:
A large number of work items are placed onto the thread pool work queue (by Task.Run). The thread pool begins executing only as many work items as it has threads.
Each of these work items accesses the Container (i.e., Lazy<Container>.Value), so each one of these work items blocks a thread until the initialization is complete. Only the first work item accessing Container will run the initialization code.
The (asynchronous) initialization code attempts to make progress, but it needs a thread pool thread to be free in order to handle housekeeping when its awaits complete. So it is also queueing very small work items to the thread pool as necessary.
The thread pool has more work than it can handle, so it begins adding threads. Since it has a limited thread injection rate, it will only add a thread every few seconds.
The thread pool is overwhelmed with work, but it can't know which work items are the important ones. Most of its work items will just block on the Lazy<T>, which uses up another thread. The thread pool cannot know which work items are the ones from the asynchronous initialization code that will free up the other work items (and threads). So most of the threads added by the thread pool just end up blocking on other work that is having a hard time to complete since there are no thread pool threads available.
So, let's talk solutions.
IMO, the easiest solution is to remove (most of) the blocking. Allow the initialization to be asynchronous by changing the lazy type from Lazy<Container> to Lazy<Task<Container>>. The Lazy<Task<T>> pattern is "asynchronous lazy initialization", and it works by Lazy-initializing a task.
The Lazy<T> part of Lazy<Task<T>> ensures that only the first caller begins executing the asynchronous initialization code. As soon as that asynchronous code yields at an await (and thus returns a Task), the Lazy<T> part is done. So the blocking of other threads is very brief.
Then all the work items get the same Task<T>, and they can all await it. A single Task<T> can be safely awaited any number of times. Once the asynchronous initialization code is complete, the Task<T> gets a result, and all the awaiting work items can continue executing. Any future calls to the Lazy<Task<T>>.Value will immediately get a completed Task<T> which takes no time at all to await since it is already completed.
Once you wrap your head around Lazy<Task<T>>, it's pretty straightforward to use. The only awkward part is that the code for the work items now have to await the shared asynchronous initialization:
public class Do
{
private Lazy<Task<Container>> lazyContainer;
private Task<Container> ContainerTask => lazyContainer.Value;
public Do()
{
lazyContainer = new Lazy<Task<Container>>(InitializeContainer);
}
public async Task<T> ReadItemAsync<T>(string id, string partitionKey)
{
// This is the awkward part. Until you get used to it. :)
var container = await ContainerTask;
var itemResponse = await container.ReadItemAsync<T>(id, new PartitionKey(partitionKey));
return itemResponse.Resource;
}
// other methods are unchanged.
}
I have an AsyncLazy<T> type in my AsyncEx library, which is essentially the same as Lazy<Task<T>> with a few usability enhancements.
More information on this pattern:
Asynchronous lazy initialization blog post.
Recipe 14.1 "Initializing Shared Resources" in my book Concurrency in C# Cookbook, 2nd edition.
The Lazy<Task<T>> asynchronous lazy initialization pattern works great if you have a widely shared resource that may or may not need to be initialized. If you have a local resource (like a private member as in this example), and if you know you will always want it initialized, then you can make the code simpler by just using Task<T> instead of Lazy<Task<T>>:
public class Do
{
private Task<Container> ContainerTask;
public Do()
{
// Important semantic change:
// This begins initialization *immediately*.
// It does not wait for work items to request the container.
ContainerTask = InitializeContainer();
}
public async Task<T> ReadItemAsync<T>(string id, string partitionKey)
{
var container = await ContainerTask;
var itemResponse = await container.ReadItemAsync<T>(id, new PartitionKey(partitionKey));
return itemResponse.Resource;
}
// other methods are unchanged.
}

Hosted service not terminating after Environment.Exit

I've got a .NET core 3.1 app with a hosted service that runs as a console application on Windows.
In case of an error I'm trying to terminate the worker with Environment.Exit(1).
Now the problem is that, if Enviroment.Exit() is called before any await in ExecuteAsync, the application does not terminate. It logs Waiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks. and then hangs indefinitely.
When I await anything before the call to Enviroment.Exit() it also logs that, but it terminates as expected.
Here is the simplest code that I could come up with to reproduce the problem.
The NotTerminatingWorker hangs forever, the TerminatingWorker terminates. The only difference is a tiny Task.Delay:
public class Program {
public static async Task Main(string[] args) {
using var host = CreateHostBuilder(args).Build();
await host.RunAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) {
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => { services.AddHostedService<NotTerminatingWorker>(); });
}
}
public class NotTerminatingWorker : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
Environment.Exit(1);
}
}
public class TerminatingWorker : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
await Task.Delay(1);
Environment.Exit(1);
}
}
I would expect that both behave the same way, but that's obviously not the case.
Any explanation for this would be greatly appreciated!
UPDATE: The application should be able to run both as a console application and as a Windows service. The non-zero return code is required to get it restarted if it crashes.
And apparently Windows does not restart services that exited with code 0.
I believe the behavior you're seeing is a side-effect of how the .NET Core runtime does its startup: it calls ExecuteAsync for each background worker and then waits for it to complete. So a synchronous ExecuteAsync can cause problems. I've used Task.Run to work around this.
In case of an error I'm trying to terminate the worker with Environment.Exit(1).
I recommend not using Environment.Exit at all. Instead, do a controlled shutdown by injecting IHostApplicationLifetime and calling StopApplication. This will trigger the stoppingToken for each of your background services, and if they ignore it, they will be forcibly terminated after a timeout.
Handling the hostLifetime events in the Main method did for me the job. This is working for me on .NET6
public static int Main(string[] args)
{
ExitCode = 0;
ILogger? logger = null;
try
{
var builder = CreateHostBuilder(args)
.Build();
var hostLifetime = builder.Services.GetRequiredService<IHostApplicationLifetime>();
logger = builder.Services.GetService<ILogger<Program>>();
// register on hostLifetime events for handling stopping and finalize
using var hostLtAppStopping = hostLifetime.ApplicationStopping.Register(() =>
{
// service is about to stop... do some cleanup stuff here
});
using var hostLtAppStopped = hostLifetime.ApplicationStopped.Register(() =>
{
logger?.LogDebug("Service graceful shout down, exit with code {exitCode}!", ExitCode);
Environment.Exit(ExitCode); // ExitCode is set by the caller of hostApplicationLifetime.StopApplication
});
// start the service
logger?.LogDebug("builder.Run()");
builder.Run();
}
catch (Exception e)
{
logger?.LogError(e, "Unhandled Exception occurred => exit with exit code 1!");
ExitCode = 1;
return ExitCode;
}
return ExitCode;
}

Why does _session.Use method not work properly?

I have a job like this:
[UnitOfWork]
public override void Execute(CompleteIRHJobArgs args)
{
var robotUserId = _userRepo.GetAll().Where(p => p.UserName == TestaLIMSWPConsts.LIMSRobot).Select(p => p.Id).First();
using (_session.Use(args.TenantId, robotUserId))
{
_instanceReciptHeaderDomainService.SetIRHToCompleteState(args.IRHIds);
}
}
I find robotUserId and set it as the current user. But after I step into method SetIRHToCompleteState, _session.UserId.Value is null. I think it is wrong behavior. My ABP version is 4.0.0.
public async Task SetIRHToCompleteState(List<int> irhIds)
{
var irhs = await _instanceHeaderRepo.GetAll().Where(p => irhIds.Contains(p.Id)).ToListAsync();
foreach (var t in irhs)
{
t.FlowState = FlowState.Completed;
t.CompleteDate = Clock.Now;
t.CompleteUserId = _session.UserId.Value;
}
}
And sometimes,
var irhs = await _instanceHeaderRepo.GetAll()...
throws exception:
System.Transactions.TransactionInDoubtException: The transaction is in doubt. ---> System.Data.SqlClient.SqlException: There is already an open DataReader associated with this Command which must be closed first. ---> System.ComponentModel.Win32Exception: The wait operation timed out
But after step into method SetIRHToCompleteState, _session.UserId.Value is null.
SetIRHToCompleteState is async and continued running after the using scope was disposed.
Since Execute is not async, you cannot await but you can call AsyncHelper.RunSync instead.
// using Abp.Threading;
using (_session.Use(args.TenantId, robotUserId))
{
AsyncHelper.RunSync(() => _instanceReciptHeaderDomainService.SetIRHToCompleteState(args.IRHIds));
}
This would also avoid the "open DataReader" error.
From aspnetboilerplate/aspnetboilerplate#1646:
it's called in a background thread which is not inside an async context. But it's not a problem since background job manager is already single threaded and does not cause to block many threads.
Hangfire implementation is also like that.

Undertow : use Hystrix Observable in Http handler

I managed to setup an Hystrix Command to be called from an Undertow HTTP Handler:
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
RpcClient rpcClient = new RpcClient(/* ... */);
try {
byte[] response = new RpcCommand(rpcClient).execute();
// send the response
} catch (Exception e) {
// send an error
}
}
This works nice. But now, I would like to use the observable feature of Hystrix, calling observe instead of execute, making the code non-blocking.
public void handleRequest(HttpServerExchange exchange) throws Exception {
RpcClient rpcClient = new RpcClient(/* ... */);
new RpcCommand(rpcClient).observe().subscribe(new Observer<byte[]>(){
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
exchange.endExchange();
}
#Override
public void onNext(byte[] body) {
exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send(ByteBuffer.wrap(body));
}
});
}
As expected (reading the doc), the handler returns immediately and as a consequence, the exchange is ended; when the onNext callback is executed, it fails with an exception:
Caused by: java.lang.IllegalStateException: UT000127: Response has already been sent
at io.undertow.io.AsyncSenderImpl.send(AsyncSenderImpl.java:122)
at io.undertow.io.AsyncSenderImpl.send(AsyncSenderImpl.java:272)
at com.xxx.poc.undertow.DiyServerBootstrap$1$1.onNext(DiyServerBootstrap.java:141)
at com.xxx.poc.undertow.DiyServerBootstrap$1$1.onNext(DiyServerBootstrap.java:115)
at rx.internal.util.ObserverSubscriber.onNext(ObserverSubscriber.java:34)
Is there a way to tell Undertow that the handler is doing IO asynchronously? I expect to use a lot of non-blocking code to access database and other services.
Thanks in advance!
You should dispatch() a Runnable to have the exchange not end when the handleRequest method returns. Since the creation of the client and subscription are pretty simple tasks, you can do it on the same thread with SameThreadExecutor.INSTANCE like this:
public void handleRequest(HttpServerExchange exchange) throws Exception {
exchange.dispatch(SameThreadExecutor.INSTANCE, () -> {
RpcClient rpcClient = new RpcClient(/* ... */);
new RpcCommand(rpcClient).observe().subscribe(new Observer<byte[]>(){
//...
});
});
}
(If you do not pass an executor to dispatch(), it will dispatch it to the XNIO worker thread pool. If you wish to do the client creation and subscription on your own executor, then you should pass that instead.)

Multithreading using Callable while having a responsive graphical interface

I'm trying to get a responsive JavaFX graphical interface while executing a cmd command.
The command I'm executing is the following.
youtube-dl.exe --audio-format mp3 --extract-audio https://www.youtube.com/watch?v=l2vy6pJSo9c
As you see this is a youtube-downloader that converts a youtube link to an mp3-file.
I want this to be executed in a second thread and not in the main FX thread.
I've solved this by implementing interface Callable in the class StartDownloadingThread.
#Override
public Process call() throws Exception {
Process p = null;
p = ExecuteCommand(localCPara1, localCPara2, localDirectory).start();
try {
Thread.sleep(30);
}catch (InterruptedException e){}
return p;
}
The method ExecuteCommand just returns a ProcessBuilder object.
I try to use Thread.sleep to make the program return to the main thread and thus making the application responsive. Unfortunately the program still freezes.
This is how the method call is called.
ExecutorService pool = Executors.newFixedThreadPool(2);
StartDownloadingThread callable = new StartDownloadingThread(parameter1, parameter2, directory);
Future future = pool.submit(callable);
Process p = (Process) future.get();
p.waitFor();
How do I make my GUI responsive using the interface Callable?
Using a executor to run a task just for you to use the get method of the Future that is returned when submitting the task does not actually free the original thread to continue with other tasks. Later you even use the waitFor method on the original thread, which is likely to take even more time than anything you do in your Callable.
For this purpose the Task class may be better suited, since it allows you to handle success/failure on the application thread using event handlers.
Also please make sure an ExecutorService is shut down after you're done submitting tasks.
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
Process p = null;
p = ExecuteCommand(localCPara1, localCPara2, localDirectory).start();
// why are you even doing this?
try {
Thread.sleep(30);
}catch (InterruptedException e){}
// do the rest of the long running things
p.waitFor();
return null;
}
};
task.setOnSucceeded(event -> {
// modify ui to show success
});
task.setOnFailed(event -> {
// modify ui to show failure
});
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(task);
// add more tasks...
// shutdown the pool not keep the jvm alive because of the pool
pool.shutdown();

Resources