I have a web api 2 controller, the client requests the controller for some kind of html generations(consists of images, files etc.). As the process needs some time and I don't want the users to wait, I have followed the following approach in the Controller :
...Controller(){
Task.Run(() =>
{
//calling heavy duty method to download files where Task.WaitAll() resides
DownloadAndRename()
});
}
DownloadAndRename(){
//created some child task here and run them in task.waitall()
//Task.WaitAll() here
}
I have created tasks for every file to download, rename and other processes. Then execute them in Task.WaitAll().
When I locally run the application, everything is okay. But when I deploy to my test server, it was throwing following exception:
Message: System.Threading.ThreadAbortException: Thread was being aborted.
P.S. In my pc, I have only one application running in the app pool, whereas in my test server there are 8 in that particular pool.
How can I overcome the exception?
Update 1: I have tried by removing the task.WaitAll and do the implementation without using Task. Still, I get the thread abort error, I think somehow the Task.Run() get timed out.
I think the issue is a simple misunderstanding of task implementation.
If you want the task to run immediately as a background task, you can add async keyword and Task return type to the Controller action and make DownloadAndRename() async and make it return a Task and then await DownloadAndRename() from inside the controller action scope. The calling thread won't be blocked this way and any code after the task will not be executed until the returned task is complete.
async Task Controller()
{
await DownloadAndRename();
}
If that still doesn't work after removing
Task.WaitAll(), I'd have a read of this as it might genuinely be
timing out as you said or could be exceptioning for another reason:
Why am i getting "Thread was being aborted" in asp.net?
Related
I'm trying to implement a hosted service and I was wondering what I am expected to do with the CancellationToken in the IHostedService.StartAsync call.
There is quite a lot in the Microsoft documentation about the cancellation token in StopAsync being essentially a timeout (5s by default) that means graceful shutdown is supposed to happen within a reasonable timeframe.
But regarding the token in StartAsync, there is not much information. If anything, the documentation specifies that the implementation shouldn't await on long running initialisation processes and should just return a long running task.
So if I support cancellation, should I pass the cancellation token to whatever creates that long running task? If yes, isn't cancelling this token a dumber version of StopAsync? Why would the framework ever do this?
And indeed, in Microsoft's own abstract BackgroundService, the implementation for StartAsyncactually completely ignores that token and creates a new one which will be cancelled on call to StopAsync...
So am I to think that the whole point of that initial token passed by the framework is actually to be used in blocking
initialisation processes nonetheless (despite the doc advising against it) by overriding the virtual BackgroundService.StartAsync method? e.g.
public class MyBackgroundService : BackgroundService
{
public override Task StartAsync(CancellationToken cancellationToken)
{
// Block the thread for initialisation with cancellation (replace Task.Delay by actual initialisation)
Task.Delay(TimeSpan.FromSeconds(10), cancellationToken).GetAwaiter().GetResult();
// Start the long running task proper
return base.StartAsync(cancellationToken);
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
// some long running process (write some actual background running code here)
return Task.Factory.StartNew(_ => {while(!stoppingToken.IsCancellationRequested){}}, null, stoppingToken);
}
}
The CancellationToken passed into the StartAsync can be used to determine if the start process should be canceled but as far as I understand, you already know that. This is written here.
Indicates that the start process has been aborted.
If you look at where StartAsync is called, you can see that the CancellationToken which is passed into the StartAsync function is linked with IHostApplicationLifetime.ApplicationStopping. As far as I understand, this token is just used if the shutdown of the application happens so early that not all hosted services have been fully started yet. However, I don't know if StopAsync will be called if the starting token is triggered (I'd have to dig further in the sources or search more in the docs).
To summarize:
The CancellationToken in the StartAsync-method should just be passed to any method called in StartAsync which supports cancellation. It will allow the app to shutdown gracefully in case the requested shutdown happens so early that the hosted service has not been fully started yet.
I am currently running my application using AWS lambda on .net core 1.1
I am finding that when I run the method below, that the final log points (_logger.Info()) and any that happen afterwards in the calling code are not completing.
I have deliberately left the "await" off the log points as I do not want the application to wait until the log is completed before moving onto the next statement as they are web calls to a third party logging service, but I do want all the logging threads to complete before the entire process is complete.
If I put "await" before all the _logger.Info then all the logs are run to completion which suggests that the code works when every method awaits the execution of the last method.
Its as if the AWS Lambda is saying that the main thread is complete therefore stop the entire process even though the logging points that are spawned to run as async are not completed yet.
I have done some research and see that .net core 2.0 has transactions (https://learn.microsoft.com/en-us/dotnet/api/system.transactions.transaction?view=netcore-2.0) but this doesnt appear to be supported by .net core 1.1
Is there any way to tell AWS Lambda to wait until all the spawned threads have been completed successfully before completing? If so could you provide me with an example?
Is something else going on here that I have misunderstood?
Here is the code:
private async Task LoadExhibitor(JObject input)
{
// Retrieve Data
_logger.Info("Retrieving Data");
// Set some variables
....
if (rawExhibitor.Error != null)
{
_logger.Warn($"No exhibitor returned from ...");
// Some error handling
...
return;
}
// Transform some information to another object
_logger.Info("Transforming exhibitor to a friendly object");
var exhibitor = await someTransformer.Transform(rawExhibitor)
_logger.Info($"Saving to elastic search ...");
// Save
await repository.SaveAsync(exhibitor, eventEditionId, locale, sessionId);
_logger.Info($"Saving to elastic search has completed");
}
I am new to azure web app, Is there any way to redirect the page first then execute the remaining code? I am stuck in situation where I have to redirect my page first, then execute the remaining code... Actually I have deployed my code on azure web app which has request timeout for about 4 mins (which is not configurable), my code take approx 15 min to execute, I want to redirect to main page and execute the remaining code in background. I have tried threads and parallel programming also still no luck.. I am not able to overcome the time frame my web page get request time out every time. Is there a way anyone can suggest?
Thanks for help!
/*functionA and functionB are not execute after redirecting.*/
private static async Task <int> functionA(para1, para2)
{
Task<int> temp1 = await functionB(y,z);
return int;
}
private static async Task<int> functionB(para1, para2)
{
return int;
}
/* This method will execute first */
private string functionC(para1, para2, para3)
{
console.log("hello world");
redirect.response("www.xyz.com");
Task<int> temp = await functionA(x,y);
return str; //return string type value
}
If you've got heavy processing that will result in a HTTP timeout, I suggest looking into offloading processing to a WebJob or Azure Function. It would work as follows:
Your Azure WebApp receives a HTTP request for a long-running operation. It gathers the necessary information, creates a Service Bus Queue message, and fires the message off. Your WebApp then responds to the user by telling them that the processing has begun.
Provision a separate WebJob or Azure Function that monitors your Service Bus Queue for messages. When a message is received, the WebJob/Function can perform the processing.
You will probably want to tell your user when the operation has completed and what the result is. You have a few options. The slickest would be to use SignalR to push notifications that the operation has completed to your users. A less sophisticated would be to have your WebJob/Function update a database record, then have your HTTP clients poll for the result.
I've personally used this pattern with Service Bus Queues/WebJobs/SignalR, and have been very pleased with the results.
Asynchronous operations in Azure storage queues and WebJobs can help in situation as stated
i have referred this
https://dev.office.com/patterns-and-practices-detail/2254
I am successfully able to call the Web Api deployed on below link from mobile app or console app.
https://dposapi.azurewebsites.net/DPosApi/v1/Configurations/GetAll
Problem is that when i put this call in BackgroundTask in a RunTime Component project and triggers the background task from mobile app than execution hangs on the line of code where i am calling the Web Api. Sample is available on below link.
https://github.com/imranshabbir/Sample
What could be the problem?
Your run method should be async, like this: (note the await before FillProducts() )
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferal = taskInstance.GetDeferral();
// do your task here
await FillProducts();
deferal.Complete();
}
Btw. are you sure that the
"execution hangs on the line of code where i am calling the Web Api"
?
In your current code the problem is that the background task is finished before you get the results (without the await the execution hits the deferal.Complete(); line earlier). So in that case you just don't see the results, but that should not be a hang.
But anyway... async/await is the answer.
I've got a situation where An activity kicks off an async task (to synchronize data with the server) and then navigates to a login view. If the user is "too quick" to log in, the app crashes with a ForeignKeyException because some of the records from the async task don't exist yet in the local database.
I want the user to be taken to the login screen quickly, but I still need to wait for the Task that was kicked off in the MvxApplication.Initialize() method before triggering the login code.
Essentially like this
App First Launches
MvxActivity.Initialize() {
Task.Factory.StartNew(() = > new SyncEngine().TwoWaySync());
RegisterAppStart<AuthViewModel>();
}
Then AuthViewModel is quickly displayed to the user, all the while, the SyncEngine().TwoWaySync() task is still running.
User fills in the form and clicks the [Login] button.
App must wait for the SyncEngine().TwoWaySync() task to complete before executing the LoginCommand().
Since we're using MvvmCross, do we use the Messenger Plugin to notify when the task is complete, or should we implement some form of Thread Queueing? If it's Thread Queueing, what's the right way to approach this in a PCL?