how to cancel HostingEnvironment.QueueBackgroundWorkItem - asp.net

Is there a way to cancel background task made with HostingEnvironment.QueueBackgroundWorkItem?
There is CancellationToken which notifies if tasks was cancelled but how can i do it?
Refering to https://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx
A successful cancellation involves the requesting code calling the CancellationTokenSource.Cancel method
OK. Where can i get access to CancellationTokenSource?

After few trials i came up with the soulution:
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct);
var cancellationToken = linkedTokenSource.Token;
return Task.Factory.StartNew(() =>
{
// do stuff on background
}, cancellationToken);
});
Update:
Indeed, task is not needed. Thanks svick for bringing that up.
Here is a bit more detailed code sample without task.
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct);
// following is a dummy method, but you get the idea.
// StoreCancellationTokenSourceSoItCanBeUsedSomewhereElse(linkedTokenSource);
var cancellationToken = linkedTokenSource.Token;
try
{
while(true)
{
cancellationToken.ThrowIfCancellationRequested();
// do bg stuff
}
}
catch (OperationCanceledException ex)
{
// either token is in cancelled state
}
});

The signature of HostingEnvironment.QueueBackgroundWorkItem is:
public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
This means that a work item gets access to a CancellationToken. But I don't think that's useful in your case. From the documentation:
The provided CancellationToken will be signaled when the application is shutting down.
If you want to cancel the workItem based on some other condition, you can use a separate CancellationToken, which you create from a CancellationTokenSource. For example, to cancel a work item if it doesn't start within 10 seconds:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
HostingEnvironment.QueueBackgroundWorkItem(_ =>
{
cts.Token.ThrowIfCancellationRequested();
// the code of the work item goes here
});
This will technically still start the work item, even if the CancellationToken is cancelled, but it won't do anything.
Note that cancellation is always cooperative. This means that if you have a long-running work item, and you want to cancel it in the middle of its execution, you will need to keep checking the CancellationToken periodically.

Related

Rebus saga data state issue

I'm trying out the simple deferred message timeout pattern in Rebus along the outline here http://mookid.dk/oncode/archives/3043 in order to have alternative behaviors depending on whether or not I receive a timely response from an other service hooked up to the same bus. Code has been modified to use async/await.
(yes, I know that article is really about unit testing. I'm just trying out the same timeout thing)
The handler in my case is a saga. Two message send operations are awaited as the last two calls of the handler of the message that starts the saga. First message uses request/reply from the external service and the reply is also eventually handled in the same saga.
Second message is a deferred message that is supposed to enforce the alternative action in case timeout occurs, just like in the Rebus unit test example. I've verified that messages are sent from and received by the saga/handler without any problems. It looks something like this:
public class TestSaga : Saga<TestSagaData>, IAmInitiatedBy<SomeMessage>, IHandleMessages<SomeReply>, IHandleMessages<TimeOutMessage>
{
private readonly IBus _bus;
public TestSaga(IBus bus)
{
_bus = bus;
}
protected override void CorrelateMessages(ICorrelationConfig<TestSagaData> config)
{
config.Correlate<SomeMessage>(s => s.Identifier, d => d.OriginalMessageIdentifier);
config.Correlate<SomeMessage>(s => s.Tag, d => d.CorrelationIdentifier);
config.Correlate<SomeReply>(s => s.Tag, d => d.CorrelationIdentifier);
config.Correlate<TimeOutMessage>(s => s.Tag, d => d.CorrelationIdentifier);
}
public async Task Handle(SomeMessage message)
{
if (!IsNew)
return;
Data.CorrelationIdentifier = message.Tag;
Data.OriginalMessageIdentifier = message.Identifier;
Data.ReplyReceived = false;
await _bus.Send(new SomeRequest {Tag = message.Tag});
await _bus.Defer(TimeSpan.FromSeconds(30), new TimeOutMessage() {Tag = message.Tag});
}
public async Task Handle(SomeReply message)
{
// Even if we would get here loooong before...
Data.ReplyReceived = true;
await DoStuffIfNotTimedout();
}
public async Task Handle(TimeOutMessage message)
{
// ...this, DoStuffIfTimeout below is always called
// since state is preserved from the _bus.Defer call. Correct?
if (!Data.ReplyReceived)
await DoStuffIfTimedout();
}
private async Task DoStuffIfNotTimedout()
{
// some more async stuff here
MarkAsComplete();
}
private async Task DoStuffIfTimedout()
{
// some more async stuff here
MarkAsComplete();
}
}
I have added a boolean saga data flag/property to indicate that the reply to the first message was received first, setting it to false initially before the both await Send/Defer calls
and setting it to true immediately in the message handler of the reply.
The flag was supposed to be used to prevent the timeout actions to start in case the deferred timeout thing was received after the first reply but before the subsequent actions were done with and the saga marked completed.
However, in this case the state of the saga seems to 'follow' the message received. So if the first message reply handler is entered first and sets the saga data flag to true. Then when the deferred message handler is entered later,
something has reset the flag again, seemingly ignoring the action taken in the first reply handler (setting the flag true). Not sure whether the 'Revision' number of the saga is supposed to change or not but it remains unchanged (zero) all the time it seems.
Also noted that it doesn't matter if the timeout occurs long after the reply handler is entered, when the timeout handler is entered, the the flag is 'false'.
Is this saga state behavior by design? I thought saga state would somehow be persisted between message handler calls. If it's the wrong behavior, what could possibly cause it?
I quite new to Rebus so I'm sure I've misunderstood something here but in that case I would like to know what :).
Transport used under the hood is RabbitMQ.
Test code: saga state test

Parallel httprequest in UWP app

I'm creating an app that requires todo parallel http request, I'm using HttpClient for this.
I'm looping over the urls and foreach URl I start a new Task todo the request.
after the loop I wait untill every task finishes.
However when I check the calls being made with fiddler I see that the request are being called synchronously. It's not like a bunch of request are being made, but one by one.
I've searched for a solution and found that other people have experienced this too, but not with UWP. The solution was to increase the DefaultConnectionLimit on the ServicePointManager.
The problem is that ServicePointManager does not exist for UWP. I've looked in the API's and I thought I could set the DefaultConnectionLimit on HttpClientHandler, but no.
So I have a few Questions.
Is DefaultConnectionLimit still a property that could be set somewhere?
if so, where do i set it?
if not, how do I increase the connnectionlimit?
Is there still a connectionlimit in UWP?
this is my code:
var requests = new List<Task>();
var client = GetHttpClient();
foreach (var show in shows)
{
requests.Add(Task.Factory.StartNew((x) =>
{
((Show)x).NextEpisode = GetEpisodeAsync(((Show)x).NextEpisodeUri, client).Result;}, show));
}
}
await Task.WhenAll(requests.ToArray());
and this is the request:
public async Task<Episode> GetEpisodeAsync(string nextEpisodeUri, HttpClient client)
{
try
{
if (String.IsNullOrWhiteSpace(nextEpisodeUri)) return null;
HttpResponseMessage content; = await client.GetAsync(nextEpisodeUri);
if (content.IsSuccessStatusCode)
{
return JsonConvert.DeserializeObject<EpisodeWrapper>(await content.Content.ReadAsStringAsync()).Episode;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return null;
}
Oke. I have the solution. I do need to use async/await inside the task. The problem was the fact I was using StartNew instead of Run. but I have to use StartNew because i'm passing along a state.
With the StartNew. The task inside the task is not awaited for unless you call Unwrap. So Task.StartNew(.....).Unwrap(). This way the Task.WhenAll() will wait untill the inner task is complete.
When u are using Task.Run() you don't have to do this.
Task.Run vs Task.StartNew
The stackoverflow answer
var requests = new List<Task>();
var client = GetHttpClient();
foreach (var show in shows)
{
requests.Add(Task.Factory.StartNew(async (x) =>
{
((Show)x).NextEpisode = await GetEpisodeAsync(((Show)x).NextEpisodeUri, client);
}, show)
.Unwrap());
}
Task.WaitAll(requests.ToArray());
I think an easier way to solve this is not "manually" starting requests but instead using linq with an async delegate to query the episodes and then set them afterwards.
You basically make it a two step process:
Get all next episodes
Set them in the for each
This also has the benefit of decoupling your querying code with the sideeffect of setting the show.
var shows = Enumerable.Range(0, 10).Select(x => new Show());
var client = new HttpClient();
(Show, Episode)[] nextEpisodes = await Task.WhenAll(shows
.Select(async show =>
(show, await GetEpisodeAsync(show.NextEpisodeUri, client))));
foreach ((Show Show, Episode Episode) tuple in nextEpisodes)
{
tuple.Show.NextEpisode = tuple.Episode;
}
Note that i am using the new Tuple syntax of C#7. Change to the old tuple syntax accordingly if it is not available.

How I can safely run async code, when handling messages from Messenger?

I am using MVVM, inparticular MVVMLight. For boradcasting to all of my modelviews, that no internet connection is available I am using Messenger class. The modelviews subscribe to this event in order to reload itself with offline data, inform user etc.
However, I have a problem. When I have the folowing handler:
private void HandleNoInternetMessage(NoInternetAccessMessage obj)
{
Task.Run(async () => await InitializeForOfflineInternalAsync());
}
public async Task InitializeForOfflineInternalAsync()
{
try
{
WaitingLayerViewModel.ShouldBeVisible = true;
WaitingLayerViewModel.IsBusy = true; //<--exception HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)
bool switchToOffline = await CommonViewModelProvider.InformUserOfNoInternetAccessAndChangeAppState(); //<!- CoreWindow.GetForCurrentThread().Dispatcher is null
await FilterTestItemViewModel.InitializeForOfflineAsync();
await FilterTestItemViewModel.InitializeForOfflineAsync();
WaitingLayerViewModel.ShouldBeVisible = false;
WaitingLayerViewModel.IsBusy = false;
...
}
}
I got exception HRESULT: 0x8001010E (RPC_E_WRONG_THREAD), because in InitializeForOfflineInternalAsync I am changing some properties of the viewmodel wchich are bound in XAML (or at least I think it is because of that). However, it is weird, because I am changing in other code bound properties regularly and have no problems with it (and the thread is a working thread).
Now, how can i solve that?
The messanger let me provide only delegate which is not async (which make kind of sense), so I can not have the HandleNoInternetMessage method async
I am using async await ... no explicit spawning of threads
I dont have access in VM to Dispatcher, because I am in VM which should not know about platform dependent stuff. And when I tried to use it to show a message, NullPointer excpetion was thrown when calling CoreWindow.GetForCurrentThread().Dispatcher; And again when calling from other places, no such exception was thrown
I guess the question is How I can safely run async code, which changes boudn properties, when handling messages from Messenger?
You're responding to messages that are logically events, so this is an acceptable use case for async void.
private async void HandleNoInternetMessage(NoInternetAccessMessage obj)
{
await InitializeForOfflineInternalAsync();
}
public async Task InitializeForOfflineInternalAsync()
{
try
{
WaitingLayerViewModel.ShouldBeVisible = true;
WaitingLayerViewModel.IsBusy = true;
bool switchToOffline = await CommonViewModelProvider.InformUserOfNoInternetAccessAndChangeAppState();
await FilterTestItemViewModel.InitializeForOfflineAsync();
await FilterTestItemViewModel.InitializeForOfflineAsync();
WaitingLayerViewModel.ShouldBeVisible = false;
WaitingLayerViewModel.IsBusy = false;
...
}
}
Remember that Task.Run is for CPU-bound code (as I describe on my blog).

Async GUI using WebForms and .NET 4.5 await/async

I've been looking for any simple example building async interfaces using ASP.NET WebForms. That is when an async method is done the await shall render.
This is one of the examples I've been looking at, How and When to use `async` and `await`. The implementation I've been looking for would look something like this
protected async void button1_Click(object sender, EventArgs e)
{
// Render when done
textBox1.Text += await WaitAsynchronouslyAsync(RandomNumber(2000, 4000));
// Render when done
textBox1.Text += await WaitAsynchronouslyAsync(RandomNumber(100, 1000));
}
public async Task<string> WaitAsynchronouslyAsync(int delay)
{
await Task.Delay(delay);
return string.Concat(delay, "; ");
}
private int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
This will however always render when everything is done, but at the same time. In the example above the desired result would be the second call to WaitAsynchronouslyAsync to render before the first call since it always will be less delay.
Or is it even possible using webforms? I do know how to do this in JavaScript using webapi's, websockets and whatnot and that's not the solution I desire at the moment.
As I describe on my blog, async does not change the HTTP protocol.
HTTP provides you with one response for each request. So, when an HTTP request arrives, it must execute your page to completion before sending the response.
In the ASP.NET world, await does not yield to the client/browser. Instead, it yields to the ASP.NET runtime. ASP.NET will not send the response until it sees that your processing is all done.
If you want to dynamically update a page (or partially render one), then you'll need to do it yourself using an appropriate technology (SignalR, UpdatePanel, etc).
When you use await in the manner that you did, execution flow is sequential. The first await, and only after it finishes will the second await execute.
If you want them executed concurrently, you can initiate both operations and use Task.WhenAny and assign the value of whichever task finishes first:
Task<string> slowerTask = WaitAsynchronouslyAsync(RandomNumber(2000, 4000));
Task<string> fasterTask = WaitAsynchronouslyAsync(RandomNumber(100, 1000));
List<Task<string>> tasks = new List<Task<string>> { slowerTask, fasterTask };
while (tasks.Count > 0)
{
Task<string> finishedTask = await Task.WhenAny(tasks);
tasks.Remove(finishedTask);
textBox1.Text = await finishedTask;
}

Parallel exceptions are being caught

somehow my exceptions seem to being caught by method they are executing in. Here is the code to call the method. As you can see I create a cancellation token with a time out. I register a method to call when the cancellation token fires and then I start a new task. The cancellation token appears to be working OK. As does the registered method.
var cancellationToken = new CancellationTokenSource(subscriber.TimeToExpire).Token;
cancellationToken.Register(() =>
{
subscriber.Abort();
});
var task = Task<bool>.Factory.StartNew(() =>
{
subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(anticedant =>
{
if (anticedant.IsCanceled)
{
Counter.Increment(12);
Trace.WriteLine("Request was canceled");
}
if (anticedant.IsFaulted)
{
Counter.Increment(13);
Trace.WriteLine("Request was canceled");
}
if (anticedant.IsCompleted)
{
Counter.Increment(14);
}
The next piece of code is the method that seems to be not only throwing the excetion (expected behavior. but also catching the exception.
public async override Task<bool> ProcessAsync(Message input, CancellationToken cancellationToken)
{
Random r = new Random();
Thread.Sleep(r.Next(90, 110));
cancellationToken.ThrowIfCancellationRequested();
return await DoSomethingAsync(input);
}
The exception is being thrown by the cancellation token but according to intellitrace it is being caught at the end of the method. I have tried a number of different options including throwing my own exception, but no matter what the continuewith function always executes the IsComleted or ran to completion code.
Any ideas on what I am doing wrong?
Thanks
I assume that RunAsync is the same as ProcessAsync.
The exception is being thrown by the cancellation token but according to intellitrace it is being caught at the end of the method.
Yup. Any async method will catch its own exceptions and place them on its returned Task. This is by design.
no matter what the continuewith function always executes the IsComleted or ran to completion code.
Well, let's take another look at the code:
var task = Task<bool>.Factory.StartNew(() =>
{
subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(
Consider the lambda passed to StartNew: it calls RunAsync, it ignores the Task that it returns, and then it returns true (successfully). So the Task returned by StartNew will always return successfully. This is why the ContinueWith always executes for a successfully-completed task.
What you really want is to await the Task returned by RunAsync. So, something like this:
var task = Task.Run(async () =>
{
await subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(
You're still ignoring the return value of RunAsync (the bool it returns is ignored), but you're not ignoring the Task itself (including cancellation/exception information).
P.S. I'm assuming there's a lot of code you're not showing us; using StartNew/Run to just kick off some async work and return a value is very expensive.
P.P.S. Use await Task.Delay instead of Thread.Sleep.

Resources