I have a UWP application where I have added background task support for doing certain things while my application is in background. I am doing exactly as it is mentioned here: https://msdn.microsoft.com/en-us/windows/uwp/launch-resume/create-and-register-a-background-task
I have one separate project for Background Tasks and in my package manifest file I have declared that my app uses background tasks (but "timer" task since I am using TimerTrigger). Code:
BackgroundTaskBuilder backgroundTaskBuilder = new BackgroundTaskBuilder { Name = "NotificationUpdater", TaskEntryPoint = "NamespaceOfMyBackgroundTaskInterfaceImplementation.BackgroundTask"};
backgroundTaskBuilder.SetTrigger(new TimeTrigger(15, false));
BackgroundTaskRegistration backgroundTaskRegistration = backgroundTaskBuilder.Register();
Code inside BackgroundTask class:
namespace NamespaceOfMyBackgroundTaskInterfaceImplementation
{
public sealed class BackgroundTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
//Code to run in the background
taskInstance.Canceled += OnTaskInstanceCanceled;
}
private void OnTaskInstanceCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
_logger.LogInfo("Background Agent: The Operating System requested cancellation. Reason: {0}.", reason);
}
}
}
When I close my application, after 20-25 minutes the background task gets triggered but when it starts executing the Run() method, OS cancels the execution with BackgroundTaskCancellationReason as executiontimeexceeded. Sometimes the cancellation happens right after the background task starts executing.
Note: When I use lifecycle events dropdown in VS to trigger the background task, the OS never cancels the execution and it keeps running without any issues.
Edit: I added some logging to know the timings and here is what I found:
BG Task started at 5/4/2016 5:58:25 PM
BG Task Cancelled at 5/4/2016 5:58:50 PM
So it's not even waiting for 30 seconds (which is supposed to be the time limit for the background task execution) and it terminates it in approximately 25 seconds (in some cases this time difference was as low as 20 seconds).
Related
On timer elapsed I am calling an async method at every 1.5 seconds.
In the log file I can see time difference of 300ms between start of TimerElapsed and SendMessage method.
i.e. between "OnTimerElapsed : started" and "SendMessage: started".
Although it happens rarely after windows services runs for an entire day.
private async void OnTimerElapsed(object source, ElapsedEventArgs e)
{
SourceTrace.TraceVerbose("OnTimerElapsed : started");
await SendMessage();
SourceTrace.TraceVerbose("OnTimerElapsed : completed");
}
public async Task SendMessage()
{
SourceTrace.TraceVerbose("SendMessage: started");
var sendTask = Send(); // start sending
var getTask = GetData(); // update data
await Task.WhenAll(sendTask, getTask);
}
How can I get rid of such unusual high delay of 300-600ms occurring rarely and randomly?
I also tried running windows service as 'High Priority' process.
.Net framework version is 4.7.1
Update:
SourceTrace.TraceVerbose is wrapper on System.Diagnostics TraceSource and TextWriterTraceListener. It usually takes 1-2 ms to write the log.
I have created a task and provided the wait time to the task.wait() method, but the task does not wait up to the provided time and return before the wait time with completed status false.
using System;
using System.Threading;
using System.Threading.Tasks;
class Test
{
static void Main(string[] args)
{
for(int i = 0 ; i < 10 ; i++)
{
int localValue = i;
Task.Factory.StartNew(() => ProcessTask(localValue));
}
Console.ReadKey();
}
private static void ProcessTask(int thread)
{
var task = Task<int>.Factory.StartNew(() => GetSomeValue());
task.Wait(2000);
if(task.IsCompleted)
{
Console.WriteLine("Completed Thread: " + thread);
}
else
{
Console.WriteLine("Not Completed Thread " + thread);
}
}
private static int GetSomeValue()
{
Thread.Sleep(400);
return 5;
}
}
Update:
I have updated the code. When I have run this code I got the following output.
Only two tasks are completed out of 10. so I want to know what is the issue with this code?
Note: I am running this code in 4.5.2 frameworks.
The problem isn't that Task.Wait isn't waiting long enough here - it's that you're assuming that as soon as you call Task.Factory.StartNew() (which you should almost never do, btw - use Task.Run instead), the task is started. That's not the case. Task scheduling is a complicated topic, and I don't claim to be an expert, but when you start a lot of tasks at the same time, the thread pool will wait a little while before creating a new thread, to see if it can reuse it.
You can see this if you add more logging to your code. I added logging before and after the Wait call, and before and after the Sleep call, identifying which original value of i was involved. (I followed your convention of calling that the thread, although that's not quite the case.) The log uses DateTime.UtcNow with a pattern of MM:ss.FFF to show a timestamp down to a millisecond.
Here's the output of the log for a single task that completed:
12:01.657: Before Wait in thread 7
12:03.219: Task for thread 7 started
12:03.623: Task for thread 7 completing
12:03.625: After Wait in thread 7
Here the Wait call returns after less than 2 seconds, but that's fine because the task has completed.
And here's the output of the log for a single task that didn't complete:
12:01.644: Before Wait in thread 6
12:03.412: Task for thread 6 started
12:03.649: After Wait in thread 6
12:03.836: Task for thread 6 completing
Here Wait really has waited for 2 seconds, but the task still hasn't completed, because it only properly started just before the Wait time was up.
If you need to wait for task completion, you can use property Result. The Result property blocks the calling thread until the task finishes.
var task = Task<int>.Factory.StartNew(() => GetsomeValue());
int res = task.Result;
So I have a "command queue" running that pumps messages out to a TCP server in my app. When the app goes to sleep, I stop the queue. When it resumes, I restart the queue. The Start and StopQueue functions are below.
public void StartQueue()
{
Task.Run(async () =>
{
while (true)
{
if (_cancellationToken.IsCancellationRequested)
{
break;
}
await Task.Delay(Hz10);
await UpdateAsync();
}
}, _cancellationToken);
}
public void StopQueue()
{
if (_cancellationToken.IsCancellationRequested) return;
_cancellationTokenSource.Cancel();
}
I can verify through the debugger that the queue is stopped successfully when the app goes to sleep (for example, pressing Home on an iPhone twice). I can also verify through the debugger that StartQueue is called when the app resumes (regains focus). However, none of my breakpoints in the Task.Run are hit after that. This leads me to believe the thread is not actually being recreated, as no breakpoints are hit in UpdateAsync or the task itself after resume.
Just make sure to initialize a new instance of _cancellationToken prior to calling StartQueue otherwise the Task will never run because the token is already in cancelled state.
Register a background task:
string myTaskName = "Task";
foreach (var cur in BackgroundTaskRegistration.AllTasks)
if (cur.Value.Name == myTaskName)
{
return;
}
await BackgroundExecutionManager.RequestAccessAsync();
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder
{
Name = "Task",
TaskEntryPoint = "Background.Task"
};
taskBuilder.SetTrigger(new TimeTrigger(15, true));
BackgroundTaskRegistration myFirstTask = taskBuilder.Register();
Background task is created in the Windows Runtime Component as a separate class:
public sealed class Task : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
//logic, send http get request, connect to db
deferral.Complete();
}
}
When it is time to perform task- it may run random number of times (1 - 15 times) and then spontaneously terminated and no longer starts,to solve this problem need to re-register task. What could be the reason?
VS show this error when i want run task:
On Windows Phone periodic background tasks are executed at an interval of a minimum of 30 minutes.
Windows has a built-in timer that runs background tasks in 15-minute intervals. Note that on Windows Phone, the interval is 30 minutes.
(Source: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh977059.aspx?f=255&MSPPError=-2147217396)
If I were you I'd change the time interval to something more safe (such as 60 minutes) - you can always try smaller intervals later. And take a look at the oneShot flag, which is set to true in your case. Set it to false to make your task run more than once.
Also your exception does not look healthy. You said it even occurs with the background task being empty - you should fix that, just to be safe.
I'd suggest you to manually start and debug your backgorund task a couple of times using the lifecycle feature in Visual Studio. Maybe there are other things that cause your task to die.
But first check the interval.
I am writing a library that is consuming a resource and for whatever reason the API was designed in a way that events will be raised on different threads but calls of the API has to be done on the main thread.
Let's say the API that I am trying to consume is defined as (I am going to omit event definitions):
public sealed class DodgyService
{
public void MethodThatHasToBeCalledOnTheMainThread() { ... }
}
To consume this API I have added a service on my library called Service (Yup, very original name) that will create a new task (that will run on the main thread as I am specifying a TaskScheduler that has been created from the SynchronizationContext).
Here is my implementation:
public class Service
{
private readonly TaskFactory _taskFactory;
private readonly TaskScheduler _mainThreadScheduler;
public Service(TaskFactory taskFactory, TaskScheduler mainThreadScheduler)
{
_taskFactory = taskFactory;
_mainThreadScheduler = mainThreadScheduler;
}
// Assume this method can be called from any thread.
// In this sample is called by the main thread but most of the time
// the caller will be running on a background thread.
public Task ExecuteAsync(string taskName)
{
return _taskFactory.StartNew(
() => ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(taskName),
new CancellationToken(false), TaskCreationOptions.None, _mainThreadScheduler)
.ContinueWith(task => Trace.TraceInformation("ExecuteAsync has completed on \"{0}\"...", taskName));
}
private void ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(string taskName)
{
Trace.TraceInformation("Starting \"{0}\" really long call...", taskName);
new DodgyService().MethodThatHasToBeCalledOnTheMainThread();
Trace.TraceInformation("Finished \"{0}\" really long call...", taskName);
}
}
Now, if I perform the call of my service (on the main thread) and try to wait on the main thread the application enters a deadlock as the main thread will be waiting for the tasks that has been scheduled to execute on the main thread.
How do I marshall these calls onto the main thread without blocking the entire process?
At some point I thought on performing the detection of the main thread before creating the new task but I don't want to hack this.
For anybody interested, I got a gist here with the code and a WPF app that exhibits the issue.
On btw, the library has to be written on .net framework 4.0
Edit!
I solved my issue following the advice provided by Scott Chamberlain as provided here
as the main thread will be waiting for the tasks
That's a guaranteed deadlock. A task cannot execute on the main thread until it is idle, running the dispatcher loop (aka pumping the message loop). It is that dispatcher loop that implements the magic of getting code to run on a specific thread. The main thread however won't be idle, it is "waiting for the tasks". So the task cannot complete because the main thread won't go idle, the main thread cannot go idle because the task won't complete. Deadlock city.
You must rewrite the code so your main thread won't wait. Move whatever code that appears after the wait call to another task that runs on the main thread, just like that ReallyLongCall().
Do note that you don't seem to get any mileage at all from using tasks, your snippet suggests that none of the code that matters runs on a worker thread. So you might as well call it directly, solves the problem as well.
From your example program:
private void HandleClosed(object sender, EventArgs e)
{
var list = new[]
{
_service.ExecuteAsync("first task"),
_service.ExecuteAsync("second task"),
_service.ExecuteAsync("third task")
};
//uncommenting this line blocks all three previous activities as expected
//as it drives the current main thread to wait for other tasks waiting to be executed by the main thread.
//Task.WaitAll(list);
}
Task.WaitAll is a blocking call, you can't perform blocking calls on the main thread or you will cause deadlocks. What you can do (if you are using Visual Studio 2012 or newer) is use the NuGet package Microsoft.Bcl.Async which gives async/await support to .Net 4.0.
After adding the package change the code to
private async void HandleClosed(object sender, EventArgs e)
{
var list = new[]
{
_service.ExecuteAsync("first task"),
_service.ExecuteAsync("second task"),
_service.ExecuteAsync("third task")
};
//uncommenting this line blocks all three previous activities as expected
//as it drives the current main thread to wait for other tasks waiting to be executed by the main thread.
await TaskEx.WhenAll(list);
}
and your program will no-longer deadlock (it also does not execute any code after await TaskEx.WhenAll(list); but that is because this code is running during the shutdown process and when you await it lets the shutdown continue on processing, if it was placed elsewhere like a click event you would see more normal behavior).
Another option is have a 2nd "Main Thread" and dispatch the work to that. Often when something must be run on "the main" thread are actually saying they require to be run on "a STA Windows Message pumped that the object was initially created on" thread. Here is a example how to to it (taken from here)
private void runBrowserThread(Uri url) {
var th = new Thread(() => {
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
br.Navigate(url);
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
var br = sender as WebBrowser;
if (br.Url == e.Url) {
Console.WriteLine("Natigated to {0}", e.Url);
Application.ExitThread(); // Stops the thread
}
}
#HansPassant is correct; by blocking the dispatcher thread to wait on the tasks, you prevent the tasks from ever being executed. The simplest change you could probably make would be to replace Task.WaitAll(list) with:
_taskFactory.ContinueWhenAll(
list,
tasks => { /* resume here */ });
...and then move any code which followed the call to WaitAll() into the continuation. Remember to check the task results and respond appropriately to any exceptions that might have occurred.
But unless there is some tangible benefit to using Tasks that is not apparent in your example code, I would heed Hans' advice and simply forego the Tasks in favor of synchronous calls.