RCairns
RCairns

Reputation: 155

UWP Background Task Cancellation

I have code like below which is uploading data using a background task on a timer running every 15 minutes. When there is nothing to upload my log shows

WINDOWS SYNC SUCCESS: 0m:0s:813ms

However when there is actually data to upload this takes a little longer and I end up with 2 logs

WINDOWS SYNC CANCELLED AFTER: 0m:25s:108ms - ExecutionTimeExceeded WINDOWS SYNC SUCCESS: 0m:27s:617ms

I understand that I only have 25 seconds on the background task - however my question is why is my "finally" block being executed when the OnCancelled event is being triggered?

This does not always happen which is what confuses me. Often I just get the cancelled log. Will the finally block always get called?

Also - as an aside - when I was testing this I had the device in sleep mode when the background task was triggered - not sure if this is relevant.

public sealed class BackgroundSync : IBackgroundTask
{
    CancellationTokenSource cancelTokenSource = new CancellationTokenSource();

    private DateTime startTime;
    private DateTime endTime;

    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();

        // Associate a cancellation handler with the background task.
        taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCancelled);

        try
        {
            await Task.Run(async () =>
            { 
                startTime = DateTime.Now;
                // MY PROCESSSING IN HERE
                endTime = DateTime.Now;
            });

        }
        catch (Exception e)
        {
            await DataNAVToMobile.InsertBackgroundLog("WINDOWS SYNC EXCEPTION: " + e.Message);
        }
        finally
        {           
            TimeSpan timeSpan = endTime - startTime;
            await DataNAVToMobile.InsertBackgroundLog("WINDOWS SYNC SUCCESS: " + String.Format("{0}m:{1}s:{2}ms",timeSpan.Minutes,timeSpan.Seconds,timeSpan.Milliseconds));
            _deferral.Complete();
        }

    }

    private void OnCancelled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
    {
        // The background task has been detected as idle or hung.
        // Cancel all pending async operations and return from the task.
        endTime = DateTime.Now;
        TimeSpan timeSpan = endTime - startTime;
        DataNAVToMobile.InsertBackgroundLog("WINDOWS SYNC CANCELLED AFTER: " + String.Format("{0}m:{1}s:{2}ms", timeSpan.Minutes, timeSpan.Seconds, timeSpan.Milliseconds) + " - " + reason.ToString());
        cancelTokenSource.Cancel();
    }

Upvotes: 1

Views: 1188

Answers (1)

Mehrzad Chehraz
Mehrzad Chehraz

Reputation: 5137

Background Tasks are limited to 30 seconds according to MSDN:

Background tasks are limited to 30 seconds of wall-clock usage.

Your background task receives the cancel notification at 25, then it has 5 seconds to finish its job and call the deferal.Complete method. If you refuse to cancel the code running in Run method, your task will be terminated after 5 seconds.

So I think in your case, you receive the cancellation notification but your code in the run method keeps running and reaches the finally in less than 5 seconds, and your task completes successfully without being terminated.

Note that canceling the token source does not necessarily cancel the code in the run method immediately. Your code may be at a point where cancelling the token has no immediate effect.

Upvotes: 2

Related Questions